denistepp
denistepp

Reputation: 530

React Native setState/useState of an Object

I am new to React Native and don't quite understand the concept of initial states of an object and updating the state when I have more than one property to set.

the error (edit #2):

Objects are not valid as a React child (found: object with keys {userRole}). If you meant to render a collection of children, use an array instead.

App.js

const initialLoginState = {
    userRole: null,
    userId: null,
};

const [user, setUser] = useState(initialLoginState);
const [isReady, setIsReady] = useState(false);

const restoreUser = async () => {
    const user = await authStorage.getUser();
    if (user) setUser(user);
};

if (!isReady) {
    return (
        <AppLoading
            startAsync={restoreUser}
            onFinish={() => setIsReady(true)}
            onError={console.warn}
        />
    );
}

//render
return (
    <AuthContext.Provider value={{ user, setUser }}>
        <NavigationContainer>
            {user.userRole ? <ViewTest /> : <AuthNavigator />}
        </NavigationContainer>
    </AuthContext.Provider>
);

useAuth which updates the user when I received the data:

const logIn = (data, authToken) => {
        setUser((prevState) => ({
            userRole: {
                ...prevState.userId, 
                userRole: data.USERROLE,
            },
        }));
        authStorage.storeToken(data.USERID);
    };

Upvotes: 0

Views: 711

Answers (3)

denistepp
denistepp

Reputation: 530

I was able to get the right answer with the help of @P.hunter, @Erdenezaya and @Federkun.

The problem was in the state init and setUser().

  1. App.js
    const initialLoginState = {
        userRole: null,
        userId: null,
    };

    const [user, setUser] = useState({
        initialLoginState,
    });
    const [isReady, setIsReady] = useState(false);

    const restoreUser = async () => {
        const user = await authStorage.getUser();
        if (user) setUser(user);
    };

    if (!isReady) {
        return (
            <AppLoading
                startAsync={restoreUser}
                onFinish={() => setIsReady(true)}
                onError={console.warn}
            />
        );
    }

    //syntax error was found in {user.userRole}
    return (
        <AuthContext.Provider value={{ user, setUser }}>
            <NavigationContainer>
                {user.userRole ? <ViewTest /> : <AuthNavigator />}
            </NavigationContainer>
        </AuthContext.Provider>
    );
  1. Context functionality for setting the user had to be done like this:
export default useAuth = () => {
    const { user, setUser } = useContext(AuthContext);

    const logIn = (data, authToken) => {

        setUser({ ...user, userRole: data.USERROLE });

        authStorage.storeToken(data.USERID);
    };

    const logOut = () => {
        setUser({ ...user, userRole: null });
        authStorage.removeToken();
    };

    return { user, logIn, logOut };
};

Thank you all for your help!

Upvotes: 1

P.hunter
P.hunter

Reputation: 1365

Objects are not valid as a React child (found: object with keys {userRole}). If you meant to render a collection of children, use an array instead.

    <AuthContext.Provider value={{ user, setUser }}>  // <---- the problem is here
        <NavigationContainer>
            {user.userRole ? <ViewTest /> : <AuthNavigator />}
        </NavigationContainer>
    </AuthContext.Provider>

I'm not sure what AuthContext.Provider is, but it's trying to render the object(User) as html react elements, make sure you know what sort of data the value prop of that component takes.

Upvotes: 1

Erdenezaya
Erdenezaya

Reputation: 141

You don't need prevState in functional component. user is the prevState before you set new state

const logIn = (data, authToken) => {
  setUser({...user, userRole: data.USERROLE});
  authStorage.storeToken(data.USERID);
};

Upvotes: 1

Related Questions