亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

我如何在 React 功能組件中擁有一個變量的副本,該副本不會更改?

我如何在 React 功能組件中擁有一個變量的副本,該副本不會更改?

撒科打諢 2023-01-06 15:18:51
我const foo: Array<ObjectExt> = useSelector(fooSelector);在功能組件中有一個變量。我想要這個變量的副本,從第一次加載組件開始就不會改變foo。在使用類組件時,我可以簡單地擁有const fooCopy = foo.slice();,但這在這里不起作用,因為組件每次都會重新加載并fooCopy發生變化。我如何在功能組件中實現這一點?
查看完整描述

4 回答

?
滄海一幻覺

TA貢獻1824條經驗 獲得超5個贊

只是useState將初始值作為 的副本foo。


const foo : Array<ObjectExt> = useSelector(fooSelector);

const [origFoo] = useState(foo.slice());

一旦origFoo被初始化,它就不會在重新渲染時被重新初始化。如果以后需要更新它的值,可以解構 setter:


const [origFoo, setOrigFoo] = useState(foo);

// ...

if(someCondition) setOrigFoo(foo.slice())

const {useState} = React;


function App() {

  const foo = [new Date().getTime()];

  const [origFoo] = useState(foo.slice());


  // Just so we have a way to force a rerender

  const [count, setCount] = React.useState(0);


  return (

    <div>

      <p>{JSON.stringify(foo)} </p>

      <p>{JSON.stringify(origFoo)}</p>

      <button onClick={() => setCount(count + 1)}>Update</button>

    </div>

  );

}


const rootElement = document.getElementById("root");

ReactDOM.render(

  <App />,

  rootElement

);

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>

<div id="root"></div>


查看完整回答
反對 回復 2023-01-06
?
料青山看我應如是

TA貢獻1772條經驗 獲得超8個贊

一種解決方案是在本地組件狀態中設置一個標志。如果該標志為假,則復制該值。否則,不要。



查看完整回答
反對 回復 2023-01-06
?
慕娘9325324

TA貢獻1783條經驗 獲得超4個贊

我想要這個變量的副本,從第一次加載組件開始,當 foo 加載時它不會改變。


當您使用useSelector(selector)react-redux 時,selector每次狀態更改時都會運行,如果返回值與上次運行時不同,則 react-redux 將重新渲染組件。


最簡單的方法是使用一個只返回第一次調用時獲得的值的選擇器:


const { Provider, useDispatch, useSelector } = ReactRedux;

const { createStore, applyMiddleware, compose } = Redux;


const initialState = { count: 0 };

//action types

const ADD = 'ADD';

//action creators

const add = () => ({

  type: ADD,

});

const reducer = (state, { type, payload }) => {

  if (type === ADD) {

    return { ...state, count: state.count + 1 };

  }

  return state;

};

//selectors

const selectCount = (state) => state.count;

 //function returning a function

const createSelectInitialCount = () => {

  //initialize NONE when createSelectInitialCount is called

  const NONE = {};

  let last = NONE;

  //return the selector

  return (state) => {

    //check if last value was set

    if (last === NONE) {

      //set last value (only when called the first time)

      last = selectCount(state);

    }

    return last;

  };

};


//creating store with redux dev tools

const composeEnhancers =

  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(

  reducer,

  initialState,

  composeEnhancers(

    applyMiddleware(() => (next) => (action) =>

      next(action)

    )

  )

);

const InitialFoo = React.memo(function InitialFoo(props) {

  const selectInitialCount = React.useMemo(//can also use useCallback

    createSelectInitialCount,//createSelectInitialCount() if you use useCallback

    []

  );

  const foo = useSelector(selectInitialCount);

  return (

    <div>

      <h3>initialfoo</h3>

      <pre>

        {JSON.stringify({ ...props, foo }, undefined, 2)}

      </pre>

    </div>

  );

});


const App = () => {

  const foo = useSelector(selectCount);

  const dispatch = useDispatch();

  const [other, setOther] = React.useState(0);

  const [showFoo, setShowFoo] = React.useState(true);

  const remountFoo = () => {

    setShowFoo(false);

    Promise.resolve().then(() => setShowFoo(true));

  };

  return (

    <div>

      <button onClick={() => dispatch(add())}>

        foo:{foo}

      </button>

      <button onClick={() => setOther((o) => o + 1)}>

        other{other}

      </button>

      <button onClick={remountFoo}>remount Foo</button>

      {showFoo && <InitialFoo other={other} />}

    </div>

  );

};


ReactDOM.render(

  <Provider store={store}>

    <App />

  </Provider>,

  document.getElementById('root')

);

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>

<div id="root"></div>

另一種方法是使用 React.memo 和忽略 foo 的自定義比較函數來創建純組件:

const { Provider, useDispatch, useSelector } = ReactRedux;

const { createStore, applyMiddleware, compose } = Redux;


const initialState = { count: 0 };

//action types

const ADD = 'ADD';

//action creators

const add = () => ({

  type: ADD,

});

const reducer = (state, { type, payload }) => {

  if (type === ADD) {

    return { ...state, count: state.count + 1 };

  }

  return state;

};

//selectors

const selectCount = (state) => state.count;

//creating store with redux dev tools

const composeEnhancers =

  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(

  reducer,

  initialState,

  composeEnhancers(

    applyMiddleware(() => (next) => (action) =>

      next(action)

    )

  )

);

const InitialFoo = React.memo(

  function InitialFoo(props) {

    return (

      <div>

        <h3>initialfoo</h3>

        <pre>{JSON.stringify(props, undefined, 2)}</pre>

      </div>

    );

  },

  //custom compare function when returning false

  //  component will re render

  ({ other }, { other: newOther }) => {

    return other === newOther;

  }

);

const InitialFooContainer = (props) => {

  const foo = useSelector(selectCount);

  //store foo in ref, will never change after mount

  const fooRef = React.useRef(foo);

  const newProps = { ...props, foo: fooRef.current };

  return <InitialFoo {...newProps} />;

};


const App = () => {

  const foo = useSelector(selectCount);

  const dispatch = useDispatch();

  const [other, setOther] = React.useState(0);

  const [showFoo, setShowFoo] = React.useState(true);

  const remountFoo = () => {

    setShowFoo(false);

    Promise.resolve().then(() => setShowFoo(true));

  };

  return (

    <div>

      <button onClick={() => dispatch(add())}>

        foo:{foo}

      </button>

      <button onClick={() => setOther((o) => o + 1)}>

        other{other}

      </button>

      <button onClick={remountFoo}>remount Foo</button>

      {showFoo && (

        <InitialFooContainer foo={foo} other={other} />

      )}

    </div>

  );

};


ReactDOM.render(

  <Provider store={store}>

    <App />

  </Provider>,

  document.getElementById('root')

);

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>

<div id="root"></div>


查看完整回答
反對 回復 2023-01-06
?
富國滬深

TA貢獻1790條經驗 獲得超9個贊

我用來完成此功能的解決方案是復制foo,例如商店中的東西initialFoo,然后在需要的組件中挑選它。



查看完整回答
反對 回復 2023-01-06
  • 4 回答
  • 0 關注
  • 130 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號