1

When I log the values from snap parameter it is displaying the values there but the rows created by renderTable function aren't rendered in a browser.

function Employees() {
  const rootRef = firebase
    .database()
    .ref()
    .child("Employees");

  const renderTable = () => {
    var i = 0;
    return rootRef.on("value", snap => {
      snap.forEach(keys => {
        i++;
        return (
          <tr key={keys}>
            ...
          </tr>
        );
      });
    });
  };

  return (
    <div className={styles.Employee}>
      <h1 className={styles.header}>Employees</h1>
      <table>
        <thead>
          <tr>
            ...
          </tr>
        </thead>
        <tbody>{renderTable()}</tbody>
      </table>
    </div>
  );
}

export default Employees;

1
  • Instead of using the snap.forEach method, use the return snap.map then all your returned statements will be rendered. Commented Nov 25, 2019 at 13:04

3 Answers 3

1

Seems like firebase's on() method invokes callback asynchronously. You must change your approach and use state and lifecycle in your React component, ie. with some help of hooks useEffect and useState as well as map method instead of forEach. In example:

function Employees() {
  const [employees, setEmployees] = useState([]);

  useEffect(() => {
    firebase
      .database()
      .ref()
      .child("Employees")
      .on("value", setEmployees);
  }, []);

  const renderTable = () => {
    return employees.map((employee, i) => {
      return (
        <tr key={keys}>
          ...
        </tr>
      );
    });
  };

  return (
    <div className={styles.Employee}>
      <h1 className={styles.header}>Employees</h1>
      <table>
        <thead>
          <tr>
            ...
          </tr>
        </thead>
        <tbody>{renderTable()}</tbody>
      </table>
    </div>
  );
}

export default Employees;

Sign up to request clarification or add additional context in comments.

2 Comments

This is exactly what i did first but i didnt work. Im returning an Object array so when i use .map it show error that Employee.map() is not a function.
Perhaps the snap object is not an array but an 'array-like' object. Try this: useEffect(() => { firebase .database() .ref() .child("Employees") .on("value", snap => setEmployees([...snap])); }, []);
0

enter image description hereThis the where rootRef is refering to

Comments

0

So I updated this and it kinda works.When I log The Emp attribute in JSX it contains an array of Table rows which is how it is suppose to be. When I do this it is Rendering the last node of array. and when i use .map function on it to render all of the array it shows this error TypeError: Emps.map is not a function. How else am i suppose to render this array?

function Employees() {
const rootRef = firebase.database().ref().child("Employees")
var i = 0
const [Emps, setEmployees] = useState([])

useEffect(() => {
    rootRef.on('value', snap => {
        snap.forEach(keys => {
        i++
        setEmployees(
            <tr>
                <td>{i}</td>
                <td>{keys.child("Name").val()}</td>
                <td>{keys.child("employee_type").val()}</td>
                <td>{keys.child("email").val()}</td>            
                <td>{keys.child("phoneNum").val()}</td>
                <td>
                   <input className={styles.view} name="view" type="submit" value="View"/>
                </td>                   
            </tr>
            )
        })
    })
}, [])

return (
    <div className={styles.Employee}>
        <h1 className={styles.header}>Employees</h1>
        <table>
            <thead>
                <tr>
                    <th scope="col">#</th>
                    <th scope="col">Name</th>
                    <th scope="col">Employee Type</th>
                    <th scope="col">Email</th>
                    <th scope="col">Phone #</th>
                    <th scope="col">Action</th>
                </tr>
            </thead>
            <tbody>
                {
                    Emps
                }
            </tbody>
        </table>
    </div>
)

}

export default Employees

5 Comments

You shouldn't render JSX in the callback of the on() method. It renders only the last row, because setEmployees is invoked in each iteration of the forEach method and thus the next call always overrides the previous one. In the end, last call of the setEmployees function overrides the state.
So does that mean Employees array has all 10 items but all of them are the last one? Because i logged array length it says 10 undifined..
Thanks Hyster Instead of adding JSX into setEmployees i pushed it in in local array and stored that array in setEmployees(items) outside the loop. I rendered {Emp} and all items got Rendered. Thanks alot Huge Help
That's not what I meant and it's a very bad solution xD But I'm glad it's working :)
I see what you mean now xD So what else can i do. Please tell

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.