1

I new here in React Js With Laravel Php Framework.

The Problem: Is it possible to get every array object to my API and fetch it in every section.because i got an error in my console that says

Uncaught TypeError: this.state.missions.map is not a function. I don't know what the problem is but the main goal is to get every object and the loop must be in specific div section in the views

Ex. If i already get the array object of mission and store

<div className="mission">
  the object of mission must be here.
</div>

<div className="store">
  the object of store must be here.
</div>

and other object. etc

My Controller:

public function index() {



    $content_mission = DB::table('content_structure')
    ->where('content_pages','=','Home')
    ->where('content_section','=','Mission-Vision')
    ->where('status','=','Active')
    ->orderBy('content_id','Desc')
    ->limit(1)
    ->get();

    $content_store = DB::table('content_structure')
    ->leftJoin('content_upload_assets','content_structure.content_id','=','content_upload_assets.cid')
    ->where('content_pages','=','Home')
    ->where('content_section','=','Store')
    ->where('status','=','Active')
    ->orderBy('content_id','Desc')
    ->limit(1)
    ->get();

    return response()->json(
        array(


        'mission'=>$content_mission,
        'store'=>$content_store)

    );

}

My Components:

export default class Content extends Component {

    constructor() {
        super();
        this.state = {
            missions: [],
            store: [],

        }

    }

    componentWillMount() {
        axios.get('/api/contents').then(response => {
            this.setState({
                missions: response.data
            });
        }).catch(error => {
            console.log(error);
        })
    }

    render() {
        return (



            <div>

                 // this div is for mission
                <div className="mission-section">

                   <h1></h1>
                   <p></p>
                   <div className="container">
                    {this.state.missions.map(mission => <li>{mission.content}</li>)}
                    </div>

                </div>

                //this div is for store
                <div className="Store"></div>


            </div>

        )   
    }
}

if(document.getElementById('app'))
{
    ReactDOM.render(<Content/>, document.getElementById('app'));
}
il_raffa
  • 5,090
  • 129
  • 31
  • 36
DevGe
  • 1,381
  • 4
  • 35
  • 66
  • The error you indicated clearly states that `this.state.missions` is not an array or typeof array. – Meet Zaveri Sep 05 '18 at 06:15
  • how to solved it? – DevGe Sep 05 '18 at 06:16
  • It seems that you're returning an object from your API response. Can you try `response.data.missions`? – Alserda Sep 05 '18 at 06:45
  • You are fetching that state `missions` property before Api call has been completed. Also I am not sure response.data is an array. Main cause for Error : `response.data` cannot be typeof array. – Meet Zaveri Sep 05 '18 at 06:49
  • @Alserda same error – DevGe Sep 05 '18 at 06:51
  • @MeetZaveri how to fetch every query in my api controller? – DevGe Sep 05 '18 at 06:51
  • You are putting that state `missions` property(empty array which should not cause the problem) in render before Api call has been completed. Also I am not sure response.data is an array. Main cause for Error : `response.data` cannot be typeof array. – Meet Zaveri Sep 05 '18 at 06:55
  • You need to change the response data structure if it is of object. So change in way that it supports array – Meet Zaveri Sep 05 '18 at 06:56

2 Answers2

0

this error is because you are fetching data async but by the time component getting rendered the data is not ready yet so you can have a flag that shows data is fetching and when the flag is flase or true as you want. you can render your data by a && operator in return like this :

{this.state.flag && this.state.missions.map(mission => <li>{mission.content}</li>)}

or you can easily say render it when there was any data

{&& this.state.missions this.state.missions.map(mission => <li>{mission.content}</li>)}
Ehsan Jso
  • 56
  • 6
  • Question: is it okay to use multiple componentWillMount() – DevGe Sep 05 '18 at 07:34
  • as a matter of fact you should not use componentwillMount anymore you can read about it here https://stackoverflow.com/questions/41612200/in-react-js-should-i-make-my-initial-network-request-in-componentwillmount-or-co/41612993#41612993 – Ehsan Jso Sep 05 '18 at 07:40
0

From json_encode php manual:

Associative array always output as object:
{"foo":"bar","baz":"long"}

Controller

return response()->json(
    array(
      'mission'=>$content_mission,
      'store'=>$content_store
    )
);

returns json object with mission and store properties. Check this on browser network tab.

Rename componentWillMount into componentDidMount and use proper data references, sth like:

componentDidMount() {
    axios.get('/api/contents').then(response => {
        this.setState({
            missions: response.data.missions,
            store: response.data.store
        });
    }).catch(error => {
        console.log(error);
    })
}

Later in render it's safe to use

{this.state.missions.map(mission => <li>{mission.content}</li>)}

as initially this.state.missions is an empty array and will be updated with loaded array - earlier value was updated with an object.

This:

{this.state.missions && this.state.missions.map(mission => <li>{mission.content}</li>)}

would be good hint for deeper references (f.e. this.state.missions.tasks) unavailable in initial state. In this case it should be rather

{(this.state.missions.length>0) && this.state.missions.map(mission => <li>{mission.content}</li>)}

This condition can be used to replace entire view:

render() {
  if (!this.state.missions.length) return <Loading />
  return (
    // title
    // missions map
    // store map

avoiding conditions in many places.

xadm
  • 8,219
  • 3
  • 14
  • 25