1

请参阅下面的片段。

通过做这个:

React.useState(()=>getInitialState2());

您避免在每次渲染时运行getInitialState2()used 。useState

但这似乎不起作用useReducer

问题

有没有办法避免在每次渲染的钩子上运行initialState参数中使用的函数?useReducer

function App() {
  
  const [state,dispatch] = React.useReducer(reducer,getInitialState());
  const [state2,setState2] = React.useState(()=>getInitialState2());
  
  return(
    <React.Fragment>
      <div>
        State: {state}
      </div>
      <div>
        State2: {state2}
      </div>
      <div>
        <button onClick={() => dispatch({type: "INCREMENT"})}>+</button>
        <button onClick={() => dispatch({type: "DECREMENT"})}>-</button>
      </div>
    </React.Fragment>
  );
}

function getInitialState() {
  console.log("From getInitialState...");
  return 0;
}

function getInitialState2() {
  console.log("From getInitialState2...");
  return 0;
}

function reducer(state,action) {
  switch(action.type) {
    case "INCREMENT": {
      return state + 1;
    }
    case "DECREMENT": {
      return state - 1;
    }
    default: {
      return state;
    }
  }
}

ReactDOM.render(<App/>, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>

4

2 回答 2

3

您通过调用它在每个渲染上运行它。要使初始化变得惰性,请传递一个函数。此外,惰性初始化是useReducer. 无论您作为第二个参数提供什么,useReducer都将传递给惰性初始化函数,但您可以忽略它。

const [state,dispatch] = React.useReducer(reducer, null, getInitialState);

或者用箭头函数包装它,如果你需要用 props 中的值初始化它:

const [state,dispatch] = React.useReducer(reducer, null, () => getInitialState(props.something));

演示:

function App() {
  
  const [state,dispatch] = React.useReducer(reducer,null,getInitialState);
  const [state2,setState2] = React.useState(()=>getInitialState2());
  
  return(
    <React.Fragment>
      <div>
        State: {state}
      </div>
      <div>
        State2: {state2}
      </div>
      <div>
        <button onClick={() => dispatch({type: "INCREMENT"})}>+</button>
        <button onClick={() => dispatch({type: "DECREMENT"})}>-</button>
      </div>
    </React.Fragment>
  );
}

function getInitialState() {
  console.log("From getInitialState...");
  return 0;
}

function getInitialState2() {
  console.log("From getInitialState2...");
  return 0;
}

function reducer(state,action) {
  switch(action.type) {
    case "INCREMENT": {
      return state + 1;
    }
    case "DECREMENT": {
      return state - 1;
    }
    default: {
      return state;
    }
  }
}

ReactDOM.render(<App/>, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>

于 2020-05-16T11:23:09.083 回答
2

由于每次渲染发生时组件都会重新运行,因此一种选择是仅在组件外部检索一次初始状态:

const initialState1 = getInitialState();
function App() {
  
  const [state,dispatch] = React.useReducer(reducer, initialState1);
  const [state2,setState2] = React.useState(()=>getInitialState2());
  
  return(
    <React.Fragment>
      <div>
        State: {state}
      </div>
      <div>
        State2: {state2}
      </div>
      <div>
        <button onClick={() => dispatch({type: "INCREMENT"})}>+</button>
        <button onClick={() => dispatch({type: "DECREMENT"})}>-</button>
      </div>
    </React.Fragment>
  );
}

function getInitialState() {
  console.log("From getInitialState...");
  return 0;
}

function getInitialState2() {
  console.log("From getInitialState2...");
  return 0;
}

function reducer(state,action) {
  switch(action.type) {
    case "INCREMENT": {
      return state + 1;
    }
    case "DECREMENT": {
      return state - 1;
    }
    default: {
      return state;
    }
  }
}

ReactDOM.render(<App/>, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root" />

于 2020-05-16T11:26:45.950 回答