从提交处理函数内部更新 react/redux 状态
Updating react/redux state from inside a submit handler function
我目前正在开发一个投票应用程序,它应该按顺序向服务器呈现问题列表和 post 答案。我处理答案没有问题,但循环问题给我带来了一些麻烦。
这是我的代码流程:
PollContainer.js - 组件
import React, { useState, useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import Question from './Questions/Question';
import { pushAnswers } from '../../actions/answers';
import { incrementCounter } from '../../actions/utils';
import Thanks from './Thanks'
const PollContainer = () => {
const dispatch = useDispatch();
const questions = useSelector(state => state.questions); // an array of questions
// a counter redux state which should increment at every click of 'submit' inside a question
const utils = useSelector(state => state.utils);
let activeQuestion = questions[utils.counter];
// function passed as a prop to a singular Question component to handle submit of an answer
const pushSingleAnswer = (answer) => {
let answersUpdate = state.answers;
answersUpdate.push(answer);
console.log(`counter:${utils.counter}`) // logs 0 everytime I click submit, while redux dev tools show that utils.counter increments at every click
if (utils.counter < questions.length ) {
setState({...state, answers: answersUpdate, activeQuestion: activeQuestion});
dispatch(incrementCounter());
} else{
dispatch(pushAnswers(state.answers));
setState({...state, isFinished: true});
}
};
const [state, setState] = useState({
isFinished: false,
activeQuestion: questions[0],
answers: [],
pushSingleAnswer
})
return (
(utils.isLoading) ? (
<h1>Loading questions...</h1>
) : (
<div>
{(!state.isFinished && <Question { ...state }/>)}
{(state.isFinished && <Thanks/>)}
</div>
))
}
export default PollContainer;
增量计数器操作:
import * as types from "./types";
export const incrementCounter = () => {
return {
type: types.INCREMENT_COUNTER,
}
}
utils.js - 减速器
// reducer handles what to do on the news report (action)
import * as types from '../actions/types';
const initialState = {
isLoading: false,
error: null,
counter: 0
}
export default (utils = initialState, action) => {
switch(action.type){
case types.LOADING_DATA:
return {...utils, isLoading: true};
case types.DATA_LOADED:
return {...utils, isLoading: false};
case types.ACTION_FAILED:
return {...utils, error: action.error};
case types.INCREMENT_COUNTER:
return {...utils, counter: utils.counter + 1} // here is the incrementing part
default:
return utils;
}
}
传递给 pushSingleAnswer
函数的 utils.counter
不会递增,但是 redux 开发工具告诉我每次我在 Question
中单击 submit
时它都会递增零件。因此,它不会呈现下一个问题。 Question
组件中的提交处理程序很简单:
const handleSubmit = (e) => {
e.preventDefault();
props.pushSingleAnswer(state);
};
我也试过:
useEffect(() => {
dispatch(incrementCounter())},
[state.answers]
);
期望每次 state.answers
更新时它都会增加,但它也不起作用。此外,redux-dev-tools 中的 counter
也不会递增。
如果有任何建议,我将不胜感激,这是我第一个认真的 react-redux 项目,我真的很喜欢使用这些技术。但是我不太明白反应如何决定在状态改变时渲染东西。
问题
- 您正在关闭存储在状态中并传递给
Question
组件的 pushSingleAnswer
回调中的初始 counter
状态。
- 您正在改变处理程序中的状态对象。
代码:
const pushSingleAnswer = (answer) => {
let answersUpdate = state.answers; // <-- save state reference
answersUpdate.push(answer); // <-- state mutation
console.log(`counter:${utils.counter}`) // <-- initial value closed in scope
if (utils.counter < questions.length ) {
setState({
...state, // <-- persists closed over callback/counter value
answers: answersUpdate,
activeQuestion: activeQuestion,
});
dispatch(incrementCounter());
} else{
dispatch(pushAnswers(state.answers));
setState({ ...state, isFinished: true });
}
};
const [state, setState] = useState({
isFinished: false,
activeQuestion: questions[0],
answers: [],
pushSingleAnswer // <-- closed over in initial state
});
{(!state.isFinished && <Question { ...state }/>)} // <-- stale state passed
解决方案
不要将回调存储在状态中并使用功能状态更新。
const pushSingleAnswer = (answer) => {
console.log(`counter:${utils.counter}`) // <-- value from current render cycle
if (utils.counter < questions.length ) {
setState(prevState => ({
...prevState, // <-- copy previous state
answers: [
...prevState.answers, // <-- copy previous answers array
answer // <-- add new answer
],
activeQuestion,
}));
dispatch(incrementCounter());
} else{
dispatch(pushAnswers(state.answers));
setState({ ...state, isFinished: true });
}
};
const [state, setState] = useState({
isFinished: false,
activeQuestion: questions[0],
answers: [],
});
{!state.isFinished && (
<Question { ...state } pushSingleAnswer={pushSingleAnswer} />
)}
我目前正在开发一个投票应用程序,它应该按顺序向服务器呈现问题列表和 post 答案。我处理答案没有问题,但循环问题给我带来了一些麻烦。
这是我的代码流程:
PollContainer.js - 组件
import React, { useState, useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import Question from './Questions/Question';
import { pushAnswers } from '../../actions/answers';
import { incrementCounter } from '../../actions/utils';
import Thanks from './Thanks'
const PollContainer = () => {
const dispatch = useDispatch();
const questions = useSelector(state => state.questions); // an array of questions
// a counter redux state which should increment at every click of 'submit' inside a question
const utils = useSelector(state => state.utils);
let activeQuestion = questions[utils.counter];
// function passed as a prop to a singular Question component to handle submit of an answer
const pushSingleAnswer = (answer) => {
let answersUpdate = state.answers;
answersUpdate.push(answer);
console.log(`counter:${utils.counter}`) // logs 0 everytime I click submit, while redux dev tools show that utils.counter increments at every click
if (utils.counter < questions.length ) {
setState({...state, answers: answersUpdate, activeQuestion: activeQuestion});
dispatch(incrementCounter());
} else{
dispatch(pushAnswers(state.answers));
setState({...state, isFinished: true});
}
};
const [state, setState] = useState({
isFinished: false,
activeQuestion: questions[0],
answers: [],
pushSingleAnswer
})
return (
(utils.isLoading) ? (
<h1>Loading questions...</h1>
) : (
<div>
{(!state.isFinished && <Question { ...state }/>)}
{(state.isFinished && <Thanks/>)}
</div>
))
}
export default PollContainer;
增量计数器操作:
import * as types from "./types";
export const incrementCounter = () => {
return {
type: types.INCREMENT_COUNTER,
}
}
utils.js - 减速器
// reducer handles what to do on the news report (action)
import * as types from '../actions/types';
const initialState = {
isLoading: false,
error: null,
counter: 0
}
export default (utils = initialState, action) => {
switch(action.type){
case types.LOADING_DATA:
return {...utils, isLoading: true};
case types.DATA_LOADED:
return {...utils, isLoading: false};
case types.ACTION_FAILED:
return {...utils, error: action.error};
case types.INCREMENT_COUNTER:
return {...utils, counter: utils.counter + 1} // here is the incrementing part
default:
return utils;
}
}
传递给 pushSingleAnswer
函数的 utils.counter
不会递增,但是 redux 开发工具告诉我每次我在 Question
中单击 submit
时它都会递增零件。因此,它不会呈现下一个问题。 Question
组件中的提交处理程序很简单:
const handleSubmit = (e) => {
e.preventDefault();
props.pushSingleAnswer(state);
};
我也试过:
useEffect(() => {
dispatch(incrementCounter())},
[state.answers]
);
期望每次 state.answers
更新时它都会增加,但它也不起作用。此外,redux-dev-tools 中的 counter
也不会递增。
如果有任何建议,我将不胜感激,这是我第一个认真的 react-redux 项目,我真的很喜欢使用这些技术。但是我不太明白反应如何决定在状态改变时渲染东西。
问题
- 您正在关闭存储在状态中并传递给
Question
组件的pushSingleAnswer
回调中的初始counter
状态。 - 您正在改变处理程序中的状态对象。
代码:
const pushSingleAnswer = (answer) => {
let answersUpdate = state.answers; // <-- save state reference
answersUpdate.push(answer); // <-- state mutation
console.log(`counter:${utils.counter}`) // <-- initial value closed in scope
if (utils.counter < questions.length ) {
setState({
...state, // <-- persists closed over callback/counter value
answers: answersUpdate,
activeQuestion: activeQuestion,
});
dispatch(incrementCounter());
} else{
dispatch(pushAnswers(state.answers));
setState({ ...state, isFinished: true });
}
};
const [state, setState] = useState({
isFinished: false,
activeQuestion: questions[0],
answers: [],
pushSingleAnswer // <-- closed over in initial state
});
{(!state.isFinished && <Question { ...state }/>)} // <-- stale state passed
解决方案
不要将回调存储在状态中并使用功能状态更新。
const pushSingleAnswer = (answer) => {
console.log(`counter:${utils.counter}`) // <-- value from current render cycle
if (utils.counter < questions.length ) {
setState(prevState => ({
...prevState, // <-- copy previous state
answers: [
...prevState.answers, // <-- copy previous answers array
answer // <-- add new answer
],
activeQuestion,
}));
dispatch(incrementCounter());
} else{
dispatch(pushAnswers(state.answers));
setState({ ...state, isFinished: true });
}
};
const [state, setState] = useState({
isFinished: false,
activeQuestion: questions[0],
answers: [],
});
{!state.isFinished && (
<Question { ...state } pushSingleAnswer={pushSingleAnswer} />
)}