javascript - 在 Redux 中设置应用挂载的存储状态

标签 javascript reactjs firebase-realtime-database redux react-redux

这是我的代码:

用户界面

export default class App extends Component {
    constructor(p) {
        super(p);
        this.state = {user: null};
    }

    setUser = () => {
        const {uid} = firebase.auth().currentUser;
        firebase.database().ref('Users').child(uid).on('value', r => {
            const user = r.val();
            this.setState({user: user});
            this.props.onLoad(this.state.user); // This is the problem
        });
    };

    componentWillMount() {
        if (firebase.auth().currentUser) {
            this.setUser();
        }
        firebase.auth().onAuthStateChanged(async () => {
            if (!firebase.auth().currentUser) {
                return null;
            }
            this.setUser();
        });
    }


    render() {
        return (
            <div className="App">
                <Nav/>
            </div>
        );
    }
}

容器

const mapStateToProps = state => ({user: state.user});
const mapDispatchToProps = dispatch => ({
    onLoad(user) {
        dispatch(setUser(user))
    }
});

export default connect(mapStateToProps, mapDispatchToProps)(App);

所以我想做的是在组件安装后立即设置一个商店。在此应用程序中进行更改之前,它会一直有效。如果我更改数据库中的数据,我的应用程序中的数据更新不会出现问题。

如果我尝试运行这个:

容器:

import {setLevel} from "../../../../../actions";
import LevelSelectUI from '../../../ui/mainUI/levelSelectUI/LevelSelectUI';

const mapStateToProps = (state, props) => ({
    user: props.user
});

const mapDispatchToProps = dispatch => ({
    onLevelChange(uid, value) {
        dispatch(setLevel(uid, value));
    }
});

export default connect(mapStateToProps, mapDispatchToProps)(LevelSelectUI)

用户界面

export default ({user = {}, onLevelChange = f => f}) => {
    const lvls = [{
        db: 'Podstawówka',
        text: 'PODSTAWOWA',
    }, {
        db: 'Gimnazjum',
        text: 'GIMNAZJALNA',
    }, {
        db: 'Liceum',
        text: 'ŚREDNIA',
    }];
    let options = [];
    if (!user.level) {
        options.push(<option key={options.length} value={null}>WYBIERZ POZIOM</option>)
    }
    options = options.concat(lvls.map((lvl, i) => {
        return (
            <option key={(i + 1) * 2} value={lvl.db}>{`SZKOŁA ${lvl.text}`}</option>
        )
    }));
    return (
        <select value={user.level}
                onChange={e => onLevelChange(e.target.value)}>
            {/*onChange={(e) => console.log(e.target.value)}>*/}
            {options.map(opt => opt)}
        </select>
    )
}

行动:

export const setLevel = (value = '') => ({
    type: C.SET_LEVEL,
    payload: value,
});

reducer :

export const level = (state = {}, action) => {
    switch (action.type) {
        case C.SET_LEVEL:
            return firebase.database().ref('Users').child(firebase.auth().currentUser.uid).child('level').set(action.payload).catch(e => console.log(e));
        default:
            return state;
    }
};

如果我运行上面的代码,我会收到此错误:

Error: You may not call store.getState() while the reducer is executing. The reducer has already received the state as an argument. Pass it down from the top reducer instead of reading it from the store.

onLoad src/AppContainer.jsx:8

   5 | const mapStateToProps = state => ({user: state.user});
   6 | const mapDispatchToProps = dispatch => ({
   7 |     onLoad(user) {
>  8 |         dispatch(setUser(user))
   9 |     }
  10 | });
  11 | 

App/_this.setUser/< src/AppUI.jsx:38

  35 |         //         else this.setState({assignedWork: undefined});
  36 |         //     });
  37 |         // }
> 38 |         this.props.onLoad(this.state.user);
     | ^  39 |     });
  40 | };
  41 | 

所以我假设我的做法是错误的。但是如何将状态设置为等于数据库中的数据呢?我尝试在商店初始化中执行此操作,但它只是出错了。

最佳答案

我最终删除了 reducer 和操作,然后这样做了:

容器:

const mapStateToProps = (state, props) => ({
    user: props.user
});

const mapDispatchToProps = () => ({
    onLevelChange(value) {
        firebase.database().ref('Users').child(firebase.auth().currentUser.uid).child('level').set(value).catch(e => console.log(e));
    }
});

export default connect(mapStateToProps, mapDispatchToProps)(LevelSelectUI)

用户界面:

export default ({user = {}, onLevelChange = f => f}) => {
    const lvls = [{
        db: 'Podstawówka',
        text: 'PODSTAWOWA',
    }, {
        db: 'Gimnazjum',
        text: 'GIMNAZJALNA',
    }, {
        db: 'Liceum',
        text: 'ŚREDNIA',
    }];
    let options = [];
    if (!user.level) {
        options.push(<option key={options.length} value={null}>WYBIERZ POZIOM</option>)
    }
    options = options.concat(lvls.map((lvl, i) => {
        return (
            <option key={(i + 1) * 2} value={lvl.db}>{`SZKOŁA ${lvl.text}`}</option>
        )
    }));
    return (
        <select value={user.level}
                onChange={e => onLevelChange(e.target.value)}>
            {/*onChange={(e) => console.log(e.target.value)}>*/}
            {options.map(opt => opt)}
        </select>
    )
}

谢谢Manjeet Singh为利德

关于javascript - 在 Redux 中设置应用挂载的存储状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54037712/

相关文章:

reactjs - ES7双冒号绑定(bind)语法解析错误

javascript - 如何在 React 中过滤 API 和 setState 中的 JSON 数据

javascript - 如何在 iOS 的 React Native 中显示从 Firebase 检索到的数据

java - List<User> 未删除 RecyclerView 适配器中包含的 POJO 对象

reactjs - React router v4 history.push 到功能组件中的相同路由(不同的查询参数)(使用 Hooks API)

java - Firebase 第一次不工作?

javascript - 之后设置 Angular Controller 变量会发生变化吗?

javascript - 如何从 angularjs 指令中获取对封闭表单元素的引用?

javascript - 使用 ref 访问对象

javascript - 同一页面上有多个 js 进度条?