Redux + React + FireBase: how to use a state when

2019-08-03 05:20发布

问题:

Hello guys and girls :)

I'm starting with Firebase && Redux and I'm having some issues with the callback on-function of firebase.database().ref() within the formular

function getAll() {

    const uid = JSON.parse(localStorage.getItem('user'))
        .uid;


    const dbRef = firebase.database()
        .ref().child('events');

    const userRef = dbRef.child(uid);

    let answer = [];

    userRef.on('value', snap => {
        let rx = snap.val();
        for (let item in snap.val()) {
            answer.push(rx[ item ]);
        }
    });

    return Promise.resolve({
        events: answer
    });
}

What was I doing ?

I've created before some actions (triggers) to call this services and this method must fire before the result be saved with reducers in the store.

This is what is expected. But,...

What is my actual reality ?

  • The method fires in time, good new :-) but,
  • The callback (as it is) fires some seconds after (1 or 1.5s) while the redux itself, very fast unit, fires and make the react render at the same time. In short, the components are rendered lots before the firebase callback gives back a value.

At the final then I need to render, reload the page, change to another route of the application so that the saved changes can be applied to render.

Since I'm beginning with redux and firebase, I'm not 100% (but only 70%) sure of this deductions, but they are the betters I could've found in this situation.

What's then the situation ?

I'm starving for any help now and thank you for any help you could provide me :)

回答1:

Hey buddy I started with Firebase this January did a whole project and I know the struggle for finding information.

The answer to your question is you need to use sagas.

https://github.com/redux-saga/redux-saga

Sagas are a way to sync your API calls so they are called before your reducer dispatches an action and makes it possible to control synchronous API calls.

For example,

function* addAnswer{
    const user = yield call(Api.addAnswer, action.payload.userId); 
    yield put({type: "REQUEST_USER_ANSWER_SUCCEEDED", user: user});
}

Sagas will wait for the call to end in yield before it continues. Then you bind this function to an action.

function* mySaga() {
    yield takeEvery("REQUEST_USER_ANSWER", fetchUser);
}

And you add to your store the redux-saga middleware

const sagaMiddleware = createSagaMiddleware() // mount it on the Store const store = createStore( reducer, applyMiddleware(sagaMiddleware) )

Basically, what happens here is each time you answer you want to be binded to the saga action REQUEST_USER_ANSWER which then if succeeds triggers the REQUEST_USER_ANSWER_SUCCEEDED which you want your reducer to be binded too. This way you know the reducer triggers only if the API call is done and succeed.

People either use Saga or Thunk in their projects which provide the same work but you absolutly need one of those.