0

I'm new on React and I have a problem in this code:

class Tests extends React.Component {

   async getTests() {
    var url = "http://127.0.0.1:100/getTestList"
    var buttons=[];
    const resp = await fetch(url);
    const data = await resp.json();

    for(let pkg in data){ 
        console.log(pkg);
        for (let cls in data[pkg]){
            console.log(cls);

            for (var i = 0; i < data[pkg][cls].length; i++) {
                let m= data[pkg][cls][i];
                buttons.push(<button value={cls}>{m}</button>);
            }
        }
    }

    return buttons;

}
render(){
    return(
        <div>
            <h4>Using .map()</h4>
            {this.getTests()}

        </div>
    )
}

}//fine classe

// ========================================

ReactDOM.render(
  <Tests />,
  document.getElementById('root')

);

I take correctly JSON Response from POST service, iterate correctly the JSON for to have an array of buttons with value and text but I have this error on Chrome:

Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead. in div (at src/index.js:95) in Tests (at src/index.js:108)

Some Tips? Thanks Regards

2
  • 1
    getTest returns a promise, not an array of react components. Commented Mar 20, 2020 at 8:23
  • how convert this in array? Commented Mar 20, 2020 at 8:27

3 Answers 3

1

I would use a function component with useState and useEffect for this case. In useEffect you can fetch your data from the endpoint then using .map() you can represent your buttons from the array what you instantiate with useState.

Please see the following solution which might resolve the issue:

const Tests = () => {
   const [buttons, setButtons] = useState([]);

   useEffect(() => {      
      async getTests() {
         const url = 'http://127.0.0.1:100/getTestList';
         const resp = await fetch(url);
         const data = await resp.json();
         const fetchedButtons = [];

         for (let pkg in data) { 
            for (let cls in data[pkg]) {
                for (var i = 0; i < data[pkg][cls].length; i++) {
                    let m = data[pkg][cls][i];
                    fetchedButtons.push(<button value={cls}>{m}</button>);
                }
            }
         }

         setButtons(fetchedButtons);
      }

      getTests();   
   }, []);

   return <div>
       <h4>Using.map()</h4>
       {/* here mapping the buttons array */}
       {
          buttons && buttons.map(e => e);          
       }
   </div>
}

I hope this helps!

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

Comments

1

getTests() is an async function and it will always return a promise object. React is complaining because you are passing a promise object to the render method.

You could store the api response in a state, and set the state in getTests method. React will update the ui on state update.

Few changes in the code.

  1. Create state
  2. Run the getTests() in componentDidMount method.
  3. Loop over the values in render method.

Example:

class Tests extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            buttons: []
        }
    }
    async getTests() {
        var url = "http://127.0.0.1:100/getTestList"
        var buttons = [];
        const resp = await fetch(url);
        const data = await resp.json();
        for (let pkg in data) {
            console.log(pkg);
            for (let cls in data[pkg]) {
                console.log(cls);
                for (var i = 0; i < data[pkg][cls].length; i++) {
                    let m = data[pkg][cls][i];
                    buttons.push({ value: cls, displayName: m });
                }
            }
        }
       this.setState( () => {
            return {
                buttons
            }
        });
    }
    async componentDidMount() {
        await getTests();
    }
    render() {
        return (
            <div>
                <h4>Using .map()</h4>
                {this.state.buttons.map(button => <button key={button.value} value={button.value}>{button.displayName}</button>) }
            </div>
        )
    }
}//fine classe
// ========================================
ReactDOM.render(
    <Tests />,
    document.getElementById('root')
);

Or you could use a functional component for this.

const ButtonGroup = () => {
    const [buttons, setButtons] = useState([]);

    useEffect(() => {
        await getTests();
    }, []);

    async function getTests() {
        const url = 'http://127.0.0.1:100/getTestList';
        const resp = await fetch(url);
        const data = await resp.json();
        const buttonData = [];
        for (let pkg in data) {
            for (let cls in data[pkg]) {
                for (var i = 0; i < data[pkg][cls].length; i++) {
                    let m = data[pkg][cls][i];
                    buttonData.push({ value: cls, displayName: m });
                }
            }
        }
        setButtons(buttonData);
    }

    return (
        <div>
            <h4>Using.map()</h4>
            {buttons.map(button =>
                (
                    <button key={button.value} value={button.value}>{button.displayName}</button>
                )
            )}
        </div>
    );
}

export default ButtonGroup;

5 Comments

You forgot to setState at the end of getTests, Make getTest an arrow so it's bound to this and do this.setState({buttons})
async getTests() { should be getTest = async () => { arrow functions are bound to this so you don't have to do this.getTest = this.getTest.bind(this) in the constructor. You should call it with this.getTests()
Yes with await this.getTests() work but i have this error after: Each child in a list should have a unique "key" prop.
yes, do you have any id with each record in the json, you have to pass a unique key in each option.
Currently I am using the option.value as the key, but not sue if it will have unique value.
-1

this error is expected. From your code, getTest method returns an array of buttons. You cannot render an array or an object from a react component.

Instead you can

  1. make buttons a state variable,
  2. set state after you prepare a local array in your getTest method.
  3. use math method to render the button tag that you defined in array.

1 Comment

you need to study and understand react anatomy and implement it.

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.