Hỏi về sử dụng Redux và get API

Hiện tại em đang tập làm 1 app sử dụng Redux.
Em có gặp một vấn đề là: không gọi được data trong state của redux
Mong mọi người chỉ giúp e ạ. em cảm ơn
Các bước thực hiện:

  • get data từ api + lưu vào state redux
  • gọi ra được danh sách items
  • click vào mỗi item sẽ chuyển sang 1 đường link dạng /champ/:id để hiện ra thông tin của item.
  • Nhưng bị lỗi data undefined, em đã gọi data của mapStateToProps ở trong componentDidMount() nhưng nó không có j cả

Đây là action của redux

export const  listChampion = () => {
    return (dispatch) => {
		return axios.get(`${DDRAGON_URL}/${VERSION}/data/en_US/champion.json`)
		.then(res => {
			// handle success
			const payload = res.data.data
			dispatch({type: 'CHAMPION_LIST', payload})
			return res.data.data
		})
		.catch(function (error) {
			// handle error
			console.log(error);
		})
    }
}

Đây là Component Champion detail

class  ChampionDetail extends Component {
    constructor(props) {
        super()
        this.state = {
            ...this.state,
            champion: {}
        }
    }

    componentDidMount() {
        this.props.getAllChampions()
        const id = this.props.match.params.id
        const { champions } = this.props
        const champion = champions.data[id] //undefined 
        console.log('champs', champions.data)
        console.log('champ', champion) //undefined 
        console.log('id', id)
    }

    render() {
        
        const { champion } = this.props
        console.log('champ', champion)
        return (
            <>
                {champion.name} 
            </>
        )
    }
    
}

const mapStateToProps = (state) => {
//Lấy data từ state đã lưu ở trang danh sách trước
    const { champions } = state
    console.log('champ',champions)
    return {
        champions
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        getAllChampions: () => {
            return dispatch(listChampion())
        }
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(ChampionDetail)

Kiểm tra trong reducer xem đã lấy được data trả về chưa !!

3 Likes

trong reducer có data ạ
nhưng trong render() nó gọi 2 lần

  • lần 1 không có gì. -> bị lỗi luôn khi muốn lấy các thuộc tính vd: const name = champions[id].name
  • lần 2 mới có data truyền vào ạ

Thì đúng rồi, lần 1 champions[id] là undefined do champions chỉ là mảng rỗng, rồi lại còn .name của undefined thì sẽ gây hỏng chương trình, để khắc phục thì set điều kiện khi nào champions[id] khác undefined thì mới tạo biến name bằng champions[id].name, hoặc có thể dung phương thức get của thư viện lodash để tạo 1 giá trị mặc định khi đọc property của 1 giá trị chẳng may bị undefined

3 Likes

a cho em hỏi nếu muốn đợi props rồi set vào state thì cần làm thế nào ạ?
e check champions[id] khác undefined ở componentDidMount() nó không nhận. Nó chỉ nhận trong render() mà trong render() thì không cho setState() ạ

Tại sao lại là champions[id], nên nhớ nếu champions là kiểu array thì id phải là kiểu number, trong khi đó cái id mà bạn đọc từ trên url thì nó sẽ luôn là dạng string nên đọc champions[id] kiểu gì cũng ra undefined, do id là string thì khi đó champions[id] sẽ được hiểu là đọc property id của 1 object champions, vậy bạn cho t hỏi champions ở đây là array hay object, nếu là array thì khi muốn kết nối đến phần tử con thì id phải là dạng number nhưng id đọc trên url sẽ là string nên bạn phải chuyển nó thành nunber

3 Likes

champions là object ạ.

nếu được thì up code lên codesandbox đi, để mọi người xem tìm nó dễ hơn.

Hiện tại e đang sử dụng 1 cách là dùng 2 hàm này để check và setState ạ. không biết như thế đã tối ưu chưa ạ? nếu còn cách khác mn chỉ giúp e với ạ

static getDerivedStateFromProps(nextProps, prevState){
        if(nextProps.champion!==prevState.champion){
            return { champion: nextProps.champion};
        }
        else return null;
    }

    componentDidUpdate(prevProps, prevState) {
        if(prevProps.champion !== this.props.champion){
            //Perform some operation here
            this.setState({champion: this.props.champion});
        }
    }

Dùng componentDidMount là đc rồi khi bạn chuyển route mới và load 1 component mới tương ứng với route đó, dùng getDerivedStateFromProps khi bạn thay đổi props nhưng ko đổi route và load component mới !

2 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?