如何使用 useEffect 使用 useSelector @redux/toolkit 从 redux 获取数据?

时间:2021-03-12 06:04:51

标签: javascript reactjs use-effect web3js redux-toolkit

我正在开发一个宠物店反应 Dapp,在某些时候要求是自动刷新宠物收养者列表..所以为此我尝试使用 useEffect 和 useSelector 从商店获取数据......但问题是它正在运行,我可以在控制台中看到它,但它不会刷新列表。要获得更新的列表,我需要刷新页面,这不是一个好主意。

问题

我打开了两个相同的 UI 选项卡,在 UI 上,我收养了一只宠物,它会更新收养者列表并隐藏收养宠物的按钮,但同时第二个 UI 不会自动更新,如果我需要查看任何更新我必须刷新 UI(页面)才能获得更新。

我希望它只刷新列表而不刷新整个页面,只更新页面的特定部分不需要刷新整个页面...

adoptionSlice.js

import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import Web3 from "web3";
import Adoption from '../contracts/Adoption'

export const initWeb3 = createAsyncThunk(
    'InitWeb3',
    async (a, thunkAPI) => {
        console.log('initWeb3 a: ', a)
        console.log('initWeb3 thunkapi: ', thunkAPI)
        console.log('initWeb3 dispatch: ', thunkAPI.dispatch)
        try {

            if (Web3.givenProvider) {
                const web3 = new Web3(Web3.givenProvider)
                await Web3.givenProvider.enable();
                web3.eth.handleRevert = true;

                const networkId = await web3.eth.net.getId();
                const network = Adoption.networks[networkId];
                const contract = new web3.eth.Contract(Adoption.abi, network.address)
                const addresses = await web3.eth.getAccounts()
                thunkAPI.dispatch(loadAdopters({
                    contract: contract,
                    address: addresses[0]
                }))
                console.log(addresses)

                return {
                    web3: web3,
                    contract: contract,
                    address: addresses[0],
                }
            }
            else {
                console.log('Error In Loading Web3')
            }
        }
        catch (err) {
            console.log('Error In Loading')
        }
    }
)

// export const loadAdopters = createAsyncThunk(
//     'LoadAdopters',
//     async (a, thunkAPI) => {
//         console.log('in loadAdopters a = ', a);
//         console.log('in loadAdopters thunkApi = ', thunkAPI);
//         console.log('in loadAdopters thunkApi state = ', thunkAPI.getState());
//         const contract = thunkAPI.getState().adoptReducer.contract;
//         console.log('loadadopters contract = ', contract);
//         const adopterList = await contract.methods.getAdopters().call()
//         return adopterList
//     }
// )
export const loadAdopters = createAsyncThunk(
    "LoadAdopters",
    async(data,thunkAPI)=>{
        const adopterList = await data.contract.methods.getAdopters().call();
        return adopterList;
    }
)

const adoptSlice = createSlice({
    name: 'AdoptSlice',
    initialState: {
        web3: null,
        contract: null,
        address: null,
        adopters: [],
        adoptInProgress: false,
        adopError: false,
        adoptErrorMessage: '',
        releasingPetStatus: false,
        releasePetError: '',
        releaseErrorMessage: ''
    },
    reducers: {
        adopt: () => { }
    },
    extraReducers: {
[initWeb3.fulfilled]: (state, action) => {
            console.log("In fullfil = ", state);
            console.log("In fullfil = ", action);
            state.web3 = action.payload.web3;
            state.contract = action.payload.contract;
            state.address = action.payload.address;
        },
        [loadAdopters.fulfilled]: (state, action) => {
            state.adopters = action.payload
        },
}

export const adopReducer = adoptSlice.reducer;
export const { adopt } = adoptSlice.actions;
<块引用>

adoptionSlice.js 用于加载 web3 并获取 loadAdopters

App.js

function App() {
  const dispatch = useDispatch();
  
  const web3 = useSelector((state)=>{
    console.log("state in app= ",state);
    return state.adoptReducer.web3
  })
 
  useEffect(()=>{
    dispatch(initWeb3());
  // eslint-disable-next-line react-hooks/exhaustive-deps
  },[])

  return (
    <div>
      <PetList></PetList>
    </div>
  );
}

export default App;

Adopter.js

import React from 'react'
import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { loadAdopters } from '../store/adoptSlice'

export const Adopters = () => {
    const dispatch = useDispatch()
    const adoptersList = useSelector((state) => {
        return state.adoptReducer.adopters
    })

    useEffect(() => {

        const interval = setInterval(() => {
            dispatch(loadAdopters())
            console.log('updated')
        }, 2000)
        return () => clearInterval(interval)
    }, [])
    return (
        <div>
            <div>Adopters List</div>
            <div>
                {
                    adoptersList.map((list, index) => (
                        list !== '0x0000000000000000000000000000000000000000' ? <div key={index}>index {index} : {list}</div> : null
                    ))
                }
            </div>
        </div>
    )
}
<块引用>

Adopter.js 从商店获取采用者列表

this is the adopters list

1 个答案:

答案 0 :(得分:0)

我想根据您所解释的内容,您尝试实现的目标是不可能的。主要有两个问题。

  • 当您在两个不同的选项卡上打开同一个 React 应用程序时,它的本质是两个不同的应用程序实例,它们没有任何共同点。每个都有自己的状态、redux 等。

  • 从您的问题中可以理解的是,您希望每当执行更改/更新您在某些数据库中的值的操作时,您都希望它反映在其他用户之间。如果您

    ,这是不可能的
  • 一个。持续显式调用 api,

    B.使用一些默默地为你调用 api 的库 更新状态(例如,SWR)

    c.使用任何发布/订阅模型(例如signalR)

所以,你应该试着先思考和解决第二个问题,它会自动解决第一个问题。