John Bradshaw
John Bradshaw

Reputation: 189

How do you get an element out of a redux reducer?

I have a react component that has a html button that when clicked calls a function that adds an element to a redux reducer and then redirects to another component. The component that is redirected to needs to set state from the reducer but it won't. I know that it is being added to the array in the reducer because I wrote it as an async await and it redirects after it gets added.

This is the original component

const Posts = () => {
  const dispatch = useDispatch();

  const getProfile = async (member) => {
    await dispatch({ type: 'ADD_MEMBER', response: member })
    console.log(member)
    window.location.href='/member'
    console.log('----------- member------------')
    console.log(post)
  }

  const socialNetworkContract = useSelector((state) => state.socialNetworkContract)


  return (
      <div>
        {socialNetworkContract.posts.map((p, index) => {
          return <tr key={index}>
    
    <button onClick={() => getProfile(p.publisher)}>Profile</button>


        </tr>})}
      </div>
  )
}

export default Posts;

This is the 'socialNetworkContract' reducer

import { connect, useDispatch, useSelector } from "react-redux";
let init = {
    posts:[],
    post:{},
    profiles:[],
    profile:{},
    members:[],
    member:{}
}
export const socialNetworkContract = (state = init, action) => {
    const { type, response } = action;
    switch (type) {
        case 'ADD_POST':
            return {
                ...state,
                posts: [...state.posts, response]
            }
        case 'SET_POST':
            return {
                ...state,
                post: response
            }
        case 'ADD_PROFILE':
            return {
                ...state,
                profiles: [...state.profiles, response]
            }
        case 'SET_PROFILE':
            return {
                ...state,
                profile: response
            }
        case 'ADD_MEMBER':
            return {
                ...state,
                members: [...state.members, response]
            }
        case 'SET_MEMBER':
            return {
                ...state,
                member: response
            }

        default: return state
    }
};

and this is the component that the html button redirects to

const Member = () => {  
  const [user, setUser] = useState({})
  const [profile, setProfile] = useState({});
  const dispatch = useDispatch();

  useEffect(async()=>{
    try {
      const pro = socialNetworkContract.members[0];
      setUser(pro)
      const p = await incidentsInstance.usersProfile(user, { from: accounts[0] });
      const a = await snInstance.getUsersPosts(user, { from: accounts[0] });
      console.log(a)
      setProfile(p)
    } catch (e) {
      console.error(e)
    }
  }, [])

  const socialNetworkContract = useSelector((state) => state.socialNetworkContract)
 
 return (
    <div class="container">

        {socialNetworkContract.posts.map((p, index) => {
          return <tr key={index}>
{p.message}
{p.replies}
        </tr>})}
          </div>
        </div>
      </div>
    </div>
  )
}

export default Member;

This is the error I get in the console

Error: invalid address (arg="user", coderType="address", value={})

The functions I'm calling are solidity smart contracts and the have been tested and are working and the element I'm trying to retrieve out of the array is an ethereum address.

incidentsInstance and snInstance are declared in the try statement but I took a lot of the code out to make it easier to understand.

Upvotes: 0

Views: 275

Answers (1)

buzatto
buzatto

Reputation: 10382

given setUser is async, your user is still an empty object when you make your request.

you could pass pro value instead:

  useEffect(async () => {
    try {
      const pro = socialNetworkContract.members[0];
      setUser(pro)
      const p = await incidentsInstance.usersProfile(pro, { from: accounts[0] });
      const a = await snInstance.getUsersPosts(pro, { from: accounts[0] });
      setProfile(p)
    } catch (e) {
      console.error(e)
    }
  }, [])

or break your useEffect in two pieces:

  useEffect(() => {
      setUser(socialNetworkContract.members[0]);
  }, [])

  useEffect(async () => {
    if (!Object.keys(user).length) return;
    try {
      const p = await incidentsInstance.usersProfile(user, { from: accounts[0] });
      const a = await snInstance.getUsersPosts(user, { from: accounts[0] });
      console.log(a)
      setProfile(p)
    } catch (e) {
      console.error(e)
    }
  }, [user])

note: fwiw, at first sight your user state looks redundant since it's derived from a calculated value.

Upvotes: 1

Related Questions