如何使用useEffect从Redux存储中的状态更新React UI

时间:2020-05-01 22:24:50

标签: reactjs redux react-redux react-hooks

我具有以下功能组件。我进行了调试,并阅读了一些有关react-redux和useEffect的文章,但仍然没有成功。在初始渲染时,我的redux存储中的状态为null,但随后进行更改以反映数据的新状态。但是,我的react UI不能反映这一点。我了解问题所在,但我不知道该如何解决。我可能会以错误的方式做事,甚至无法从redux存储中的更新状态获取数据。

这是我的组成部分:

const Games = (props) => {
    const [gamesData, setGamesData] = useState(null)
    const [gameData, setGameData] = useState(null)
    const [gameDate, setGameDate] = useState(new Date(2020, 2, 10))    
    const classes = GamesStyles()

    // infinite render if placed in 
    // useEffect array
    const {gamesProp} = props
    useEffect(() => {
        
        function requestGames() {
            var date = parseDate(gameDate)            
            try {                
                props.getGames(`${date}`)
                // prints null, even though state has changed
                 console.log(props.gamesProp)
                setGamesData(props.gamesProp)

            } catch (error) {
                console.log(error)
            }
        }    
        requestGames()
    }, [gameDate])
    

    // data has not been loaded yet
    if (gamesData == null) {
        return (
            <div>
                <Spinner />
            </div>
        )
    } else {
        console.log(gamesData)

        return (
           <div><p>Data has been loaded<p><div>
           {/* this is where i would change gameDate */}
        )
    }
}

const mapStateToProps = (state) => {
    return {
        gamesProp: state.gamesReducer.games,
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        getGames: (url) => dispatch(actions.getGames(url)),
    }
}
export default connect(mapStateToProps, mapDispatchToProps)(Games)

这是我的减速器

import {GET_GAMES} from '../actions/types'


const initialState = {
    games: null // what we're fetching from backend
}

export default function(state = initialState, action){
    switch(action.type){
        
        case GET_GAMES:
            // prints correct data from state
            //console.log(action.payload)
            
            return{
                ...state,                 
                games: action.payload
            }
           
        default:
            return state
    }
}

这是我的行动

import axios from 'axios'
import {GET_GAMES} from './types'


// all our request go here

// GET GAMES
export const getGames = (date) => dispatch => {
    
    //console.log('Date', date)
    axios.get(`http://127.0.0.1:8000/games/${date}`)
    .then(res => {
        
        dispatch({            
            type: GET_GAMES,
            payload: res.data
        })
    }).catch(err => console.log(err))

}

my state after initial render

当我将状态中的道具放置在useEffect的依存关系数组中时,状态会更新,但会导致无限渲染,因为道具正在更改。 即使我破坏了道具,也会发生这种情况。

这是在初始渲染器上更新后我的redux状态的图像。

1 个答案:

答案 0 :(得分:1)

您遇到了问题,因为您试图根据closure中的数据来设置状态。即使父数据发生更改,useEffect中的props.gamesProp也永远不会更新。

效果props.gamesProp之所以为null的原因是因为在每个渲染中,您的组件本质上都有一个props的新实例,因此当useEffect运行时,useEffect的内部部分会看到的props版本是那个渲染器上存在的东西。

组件中的任何函数(包括事件处理程序和效果)都可以从其创建的渲染中“看到”道具和状态。

https://reactjs.org/docs/hooks-faq.html#why-am-i-seeing-stale-props-or-state-inside-my-function

除非您必须在组件中修改gamesState,否则我强烈建议您不要将prop复制到该状态。

我还建议使用useDispatchuseSelector代替功能组件的连接。

根据我当前所看到的内容以及我刚刚描述的内容,对您的组件进行了一些修改:

import { useDispatch, useSelector } from 'react-redux';

const Games = (props) => {
  const gamesData = useSelector((state) => state.gamesReducer.games);
  const dispatch = useDispatch();
  const [gameData, setGameData] = useState(null);
  const [gameDate, setGameDate] = useState(new Date(2020, 2, 10));
  const classes = GamesStyles();

  // infinite render if placed in
  // useEffect array
  useEffect(() => {
    const date = parseDate(gameDate);
    try {
      dispatch(actions.getGames(`${date}`));
    } catch (error) {
      console.log(error);
    }
  }, [gameDate, dispatch]);

  // data has not been loaded yet
  if (gamesData == null) {
    return (
      <div>
        <Spinner />
      </div>
    );
  } else {
    console.log(gamesData);

    return (
      <div>
        <p>Data has been loaded</p>
      </div>
      // this is where i would change gameDate
    );
  }
};

export default Games;

如果您需要从道具中获取状态,这是钩子上的React文档必须说的:

https://reactjs.org/docs/hooks-faq.html#how-do-i-implement-getderivedstatefromprops