I was following a tutorial where you could take the star wars api and fetch data from the api to show on the website. In the tutorial, they basically show you to make a button and when you click the button, it shows the character info. But I want it to go to another page showing the details of the character using react router. Below is the code
import axios from 'axios';
import './App.css';
import List from './List';
class App extends Component {
constructor(props){
super(props);
this.state={
people: [],
}
this.getPeople=this.getPeople.bind(this);
}
getPeople(){
return axios.get("https://swapi.co/api/people")
.then((response)=>{
console.log(response.data.results);
this.setState({people: response.data.results})
})
}
componentDidMount(){
this.getPeople()
}
render(){
const {people}=this.state;
return (
<div className="App">
<List people={people}/>
</div>
);
}
}
export default App;
List.js
import React, {Component} from 'react';
import CharInfo from './CharInfo';
class List extends Component{
render(){
const people=this.props.people;
return (
<div className="">
{
people.map((p)=>{
console.log(p)
return (
<div key={p.url}>
<h1 className="char-name">{p.name}</h1>
<CharInfo charInfo={p}/>
</div>
)
})
}
</div>
);
}
}
export default List;
CharInfo.js
import React, {Component} from 'react';
class CharInfo extends Component{
constructor(props){
super(props);
this.state={
expanded: false,
}
this.open=this.open.bind(this);
this.close=this.open.bind(this);
}
open(){
this.setState({expanded: !this.state.expanded})
}
close(){
this.setState({expanded: !this.state.expanded})
}
render(){
const info=this.props.charInfo;
if(!this.state.expanded){
return <p className="btn btn-info" onClick={this.open}>Show info</p>
}
return (
<div className="user-details">
<p className="btn btn-danger" onClick={this.close}>Hide Info</p>
<ul>
<li>
<h2>Gender: {info.gender}</h2>
</li>
<li>
<h2>Birth Year: {info.birth_year}</h2>
<li><h2>Hair Color: {info.hair_color}</h2></li>
</li>
</ul>
</div>
)
}
}
export default CharInfo;
in this link, you could see the code in a codesandbox
https://codesandbox.io/s/romantic-pine-lmhvn
You need to integrate the react-router-dom library in order to navigate to different "pages" in your React application.
Working codesandbox: https://codesandbox.io/s/star-wars-api-8bbuf
App.js
import React, { Component } from "react";
import axios from "axios";
import List from "./List";
import Character from "./Character";
import { BrowserRouter, Route } from "react-router-dom";
class App extends Component {
constructor(props) {
super(props);
this.state = {
people: []
};
this.getPeople = this.getPeople.bind(this);
}
getPeople = () => {
axios.get("https://swapi.co/api/people").then(response => {
this.setState({ people: response.data.results });
});
};
componentWillMount() {
this.getPeople();
}
render() {
const { people } = this.state;
console.log(people);
return (
<BrowserRouter>
<Route
path="/"
exact
render={props => <List {...props} people={this.state.people} />}
/>
<Route
path="/char/:charName"
render={props => {
const { charName } = props.match.params;
const foundCharacter = this.state.people.find(
person => person.name.split(" ").join("") == charName
);
return <Character {...props} info={foundCharacter} />;
}}
/>
</BrowserRouter>
);
}
}
export default App;
CharInfo.js
import React, { Component } from "react";
import { Link } from "react-router-dom";
class CharInfo extends Component {
constructor(props) {
super(props);
this.state = {
expanded: false
};
this.open = this.open.bind(this);
this.close = this.open.bind(this);
}
open() {
this.setState({ expanded: !this.state.expanded });
}
close() {
this.setState({ expanded: !this.state.expanded });
}
render() {
const info = this.props.charInfo.name.split(" ").join("");
return (
<div className="user-details">
<Link className="btn btn-info" to={`/char/${info}`}>
Show info
</Link>
</div>
);
}
}
export default CharInfo;
New component: Character.js
const Character = ({ info }) => {
return (
<div>
{
<ul>
<li>
<h2>{info.name}</h2>
</li>
<li>
<h2>Gender: {info.gender}</h2>
</li>
<li>
<h2>Birth Year: {info.birth_year}</h2>
</li>
<li>
<h2>Hair Color: {info.hair_color}</h2>
</li>
{info.vehicles.length > 0 && (
<li>
<h2>Vehicles:</h2>
<ul>
{info.vehicles.map((vehicle, index) => (
<li key={index}>{vehicle}</li>
))}
</ul>
</li>
)}
</ul>
}
</div>
);
};
export default Character;
Related
I'm currently working on creating a PokeDex by using the PokeApi. I'm trying to complete the PokemonList, that will contain all the different PokemonCard buttons.
I am receiving expected ";" error for my componentDidMount and I'm unsure why.
The code for the page is
import React from "react";
import PokemonCard from "./PokemonCard";
import "../ui/PokemonList.css";
import axios from 'axios';
export default class PokemonList extends Component {
state = {
url: "https://pokeapi.co.api.v2.pokemon/",
pokemon: null
};
}
componentDidMount() {
const res = axios.get(this.state.url);
this.setState({pokemon: res.data['results'] });
}
const PokeList = () => {
return (
<section className="poke-list">
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
</section>
);
};
//export default PokeList;
It is marking the error on the { symbol after componentDidMount().
The error remains there, even after I add a semi-colon after the curly brackets, even though I don't think the semi-colon is necessary, since the guide I'm following doesn't do it.
Is there some simple rule that I'm breaking? I'm new to React / JavaScript.
edit ----------------------------------------------------
My Dashboard.Js code is
import React, { Component } from "react";
import PokeList from "../pokemon/PokemonList";
export default class Dashboard extends Component {
render() {
return (
<div>
<div className="row">
<div className="col">
<PokeList />
</div>
</div>
</div>
);
}
}
I am getting the following error now
./src/components/layout/Dashboard.js
Attempted import error: '../pokemon/PokemonList' does not contain a default export (imported as 'PokeList').
probably because
import React from "react";
import PokemonCard from "./PokemonCard";
import "../ui/PokemonList.css";
import axios from 'axios';
export default class PokemonList extends Component {
state = {
url: "https://pokeapi.co.api.v2.pokemon/",
pokemon: null
};
} <----- extra curly brace remove this
componentDidMount() {
const res = axios.get(this.state.url);
this.setState({pokemon: res.data['results'] });
}
//keep this function inside class
PokeList = () => {
return (
<section className="poke-list">
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
</section>
);
};
render() {
return(
<div>{this.Pokelist}</div>
)
}}
//export default PokeList; // <=== remove this
Your component did mount was outside the class component.
to make your current code work --
import React from "react";
import PokemonCard from "./PokemonCard";
import "../ui/PokemonList.css";
import axios from 'axios';
export const PokemonList = class PokemonList extends Component {
state = {
url: "https://pokeapi.co.api.v2.pokemon/",
pokemon: null
};
componentDidMount() {
const res = axios.get(this.state.url);
this.setState({pokemon: res.data['results'] });
}
} <==== class component ended
export const PokeList = () => {
return (
<section className="poke-list">
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
<PokemonCard />
</section>
);
};
Dashboard js
import React, { Component } from "react";
import {PokeList} from "../pokemon/PokemonList";
export default class Dashboard extends Component {
render() {
return (
<div>
<div className="row">
<div className="col">
<PokeList />
</div>
</div>
</div>
);
}
}
The first issue is invalid url.
Change url with: https://pokeapi.co/api/v2/pokemon/
See code example:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import PokemonList from "./components/PokemonList";
import "./styles.css";
class App extends Component {
render() {
return (
<div className="App">
<PokemonList />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
import React, { Component } from "react";
import axios from "axios";
import PokemonCard from "./PokemonCard";
class PokemonList extends Component {
constructor(props) {
super(props);
this.state = {
url: "https://pokeapi.co.api.v2.pokemon/",
pokemons: []
};
}
componentDidMount = () => {
axios
.get("https://pokeapi.co/api/v2/pokemon/")
.then(response => {
const data = response.data.results;
this.setState({ pokemons: data });
})
.catch(error => {
console.log(error);
});
};
render() {
const { pokemons } = this.state;
return (
<div className="pokemon-list">
{pokemons.length > 0 &&
pokemons.map(pokemon => {
return <PokemonCard pokemon={pokemon} />;
})}
</div>
);
}
}
export default PokemonList;
import React, { Component } from "react";
class PokemonCard extends Component {
render() {
const { pokemon } = this.props;
console.log(pokemon);
return (
<div className="pokemon-card">
<p>Name: {pokemon.name}</p>
<p>
Url: <a href={pokemon.url}>{pokemon.url}</a>
</p>
</div>
);
}
}
export default PokemonCard;
I'm having issues with a passed down prop. I'm trying to render an array of objects in a list. However, the prop returns the results, and then immediately turns it to 'undefined'. Open dev tools to see result in console.
Parent component:
import React, { Component } from 'react';
import './App.css';
import { SearchBar } from '../SearchBar/SearchBar.js';
import { SearchResults } from '../SearchResults/SearchResults.js';
import { Playlist } from '../Playlist/Playlist.js';
class App extends React.Component {
constructor(props){
super(props);
this.state = {
searchResults: [
{
id: 2011,
name: 'What Makes A Man',
artist: 'Man As Machine',
album: 'Nothing but a thing'
},
{
id: 2056,
name: 'Pushpin',
artist: 'Man As Machine',
album: 'Patterns'
},
{
id: 2099,
name: 'Zombie',
artist: 'Man As Machine',
album: 'Patterns'
}
],
playlistName: ''
}
}
render() {
return (
<div>
<h1>Ja<span className="highlight">mmm</span>ing</h1>
<div className="App">
<SearchBar />
<div className="App-playlist">
<SearchResults searchResults={this.state.searchResults}/>
<Playlist />
</div>
</div>
</div>
);
}
}
export default App;
the first child component:
import React from 'react';
import './SearchResults.css';
import { Tracklist } from '../Tracklist/Tracklist.js';
export class SearchResults extends React.Component {
render () {
return (
<div className="SearchResults">
<h2>Results</h2>
<Tracklist tracks={this.props.searchResults}/>
</div>
)
}
}
The destination child component:
import React from 'react';
import './Tracklist.css';
import { Track } from '../Track/Track.js';
export class Tracklist extends React.Component {
constructor(props) {
super(props);
}
renderTrackList() {
let properties = this.props.tracks;
if (properties === undefined){
return <h3>Sorry, we found no results</h3>
} else {
properties.forEach( track => {
console.log(track);
return <Track key={track.id} track={track} />;
})
}
}
render () {
return (
<div className="TrackList">
{this.renderTrackList()}
</div>
)
}
}
I have attached the other components just for clarity. They are as follows:
playlist:
import React from 'react';
import './Playlist.css';
import { Tracklist } from '../Tracklist/Tracklist.js';
export class Playlist extends React.Component {
render() {
return (
<div className="Playlist">
<input defaultValue='New Playlist'/>
<Tracklist />
<a className="Playlist-save">SAVE</a>
</div>
)
}
}
searchBar:
import React from 'react';
import './SearchBar.css';
export class SearchBar extends React.Component {
render() {
return (
<div className="SearchBar">
<input placeholder="Enter A Song, Album, or Artist" />
<a>SEARCH</a>
</div>
);
}
}
Track:
import React from 'react';
import './Track.css';
export class Track extends React.Component {
renderAction (isRemoval) {
if (this.props.isRemoval){
return <a className="Track-action" onClick={this.removeTrack}>-</a>
} else {
return <a className="Track-action" onClick={this.addTrack}>+</a>
}
}
render () {
return (
<div className="Track">
<div className="Track-information">
<h3>{this.props.track.name}</h3>
<p>{this.props.track.artist} | {this.props.track.album}</p>
</div>
<a className="Track-action">{this.renderAction}</a>
</div>
)
}
}
Please note that this is still a work in progress. So a lot of the detail and event handlers still need to be programmed.
Instead of
properties.forEach( track => {
console.log(track);
return <Track key={track.id} track={track} />;
})
write
return properties.map( track => {
console.log(track);
return <Track key={track.id} track={track} />;
})
OR
.map without return
return properties.map( track => (
<Track key={track.id} track={track} />
))
I am using BrowserRouter with App as parent component and UserInfo as child. Unable to fetch data I am getting errors as mentioned in question I am using BrowserRouter with App as parent component and UserInfo as child. Unable to fetch data I am getting errors as mentioned in question
// This is my index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { BrowserRouter, Switch, Route } from 'react-router-dom'
var UserInfo = require('./Components/UserInfo');
var routes = (
<BrowserRouter>
<Route path="/" component={App}>
<Switch>
<Route path="user/:username" component={UserInfo} />
</Switch>
</Route>
</BrowserRouter>
);
ReactDOM.render(routes, document.getElementById('root'));
registerServiceWorker();
//App.js
import React, { Component } from 'react';
import './App.css';
import PropTypes from "prop-types";
import { browserHistory } from 'react-router';
var history = require('react-router').browserHistory;
class App extends Component {
static contextTypes = {
router: PropTypes.object
}
constructor(props, context) {
super(props, context);
}
submitUser(event) {
console.log(this.refs.inputUser.value);
event.preventDefault();
this.context.router.history.push('/user/${this.refs.inputUser.value}');
}
render() {
return (
<div>
<nav className="uk-navbar-container uk-margin" uk-navbar="true">
<div className="uk-navbar-left">
<a className="uk-navbar-item uk-logo" href="/"> Github search
<span uk-icon="icon: github; ratio: 2.2" className="uk-margin-large-right"></span>
</a>
<div className="uk-navbar-item uk-navbar-right">
<form onSubmit={this.submitUser}>
<input className="uk-input uk-form-width-medium"
type="text" placeholder="Github UserName...." ref="inputUser" />
<button className="uk-button uk-button-primary">Search
<span uk-icon="search" className="uk-margin-small-right"></span>
</button>
</form>
</div>
<div className="uk-navbar-item uk-navbar-right"></div>
</div>
</nav>
<div className="uk-container-large">
{this.props.children}
</div>
</div>
);
}
}
export default App;
//UserInfo.js
import React, { Component } from 'react';
import { BrowserRouter, Link } from 'react-router-dom'
var $ = require('jquery');
class UserInfo extends Component {
constructor(props) {
super(props)
}
getInitialState() {
return {};
}
componentDidMount() {
this.fetchData();
}
componentDidUpdate(prevProps) {
if (prevProps.params.username !== this.props.params.username) {
this.fetchData();
}
}
fetchData() {
$.getJSON('https://api.github.com/users/${this.props.params.username}')
.then(res => res.json())
.then((user) => {
this.setState = { user: user }
});
}
render() {
if (!this.state.user) {
return (
<div className="uk-child-width-1-3#s uk-grid-match">Loading......</div>
)
}
var user = this.state.user;
return (
<div className="uk-child-width-1-3#s uk-grid-match" uk-grid>
<Link to={`/user/${user.login}`}>
<div className="uk-grid-small uk-flex-middle" uk-grid>
<div className="uk-width-auto">
<img className="uk-border-circle" width="60" height="60"
src={user.avatar_url} />>
</div>
<div className="uk-width-expand">
<h3 className="uk-card-title uk-margin-remove-bottom">
{user.login} ({user.name})
</h3>
<p className="uk-text-meta uk-margin-remove-top">
{user.bio}
</p>
</div>
</div>
</Link>
</div>
);
}
}
export default UserInfo;
You have some errors in the UserInfo Component.
You have not set the Initial State of user in the constructor.
No need for another then in $.getJSON().You already getting the response , just setState the user with the response and you are good to go.
class UserInfo extends React.Component {
constructor(props) {
super(props)
this.state={
user : "",
}
}
componentDidMount() {
this.fetchData();
}
componentDidUpdate(prevProps) {
if (prevProps.params.username !== this.props.params.username) {
this.fetchData();
}
}
fetchData() {
$.getJSON('https://api.github.com/users/subhanshu')
.then((res) => {
this.setState({ user : res })
},this);
}
render() {
if (!this.state.user) {
return (
<div className="uk-child-width-1-3#s uk-grid-match">Loading......</div>
)
}
var user = this.state.user;
return (
<div className="uk-child-width-1-3#s uk-grid-match" uk-grid>
<Link to={`/user/${user.login}`}>
<div className="uk-grid-small uk-flex-middle" uk-grid>
<div className="uk-width-auto">
<img className="uk-border-circle" width="60" height="60"
src={user.avatar_url} />>
</div>
<div className="uk-width-expand">
<h3 className="uk-card-title uk-margin-remove-bottom">
{user.login} ({user.name})
</h3>
<p className="uk-text-meta uk-margin-remove-top">
{user.bio}
</p>
</div>
</div>
</Link>
</div>
);
}
}
Your <BrowserRouter> should be like,
<BrowserRouter>
<Switch>
<Route path="/" component={App}>
</Switch>
</BrowserRouter>
and if App is not a generic parent and is used only to show UserInfo, inside the App component's render you can give,
<div className="uk-container-large">
<Route path="user/:username" component={UserInfo} />
</div>
I'm new to React and I've made a <Link>to go to next or previous item from dy datas(for example, if i am on user/2 view, previous link go to user/1 and next link go to user/3), the url is correctly changed but the component is not rendered at all and the datas are not reloaded at all.
I've read that it's due to the component not detecting that the children is not changing state so the parent component does not render.
I've tried to use withRouter but I've got a error : You should not use <Route> or withRouter() outside a <Router> and I'm not understanding what I'm doing so if someone has the solution and some explanation to it I would be grateful :)
App.js :
import React, { Component } from 'react';
import {
Route,
Switch,
withRouter,
} from 'react-router-dom';
import HomePage from './pages/home';
import SinglePage from './pages/single';
class App extends Component {
render() {
return (
<Switch>
<div>
<Route exact path="/" component={HomePage} />
<Route path="/:id" component={SinglePage} />
</div>
</Switch>
);
}
}
export default withRouter(App);
Single.js :
import React, { Component } from 'react';
import Details from '../components/details'
import Header from '../components/header'
import { ProgressBar } from 'react-materialize';
class SinglePage extends Component {
constructor(props) {
super(props);
this.state = {
data: { data: null },
}
}
componentDidMount() {
fetch(`http://localhost:1337/${this.props.match.params.id}`)
.then((res) => res.json())
.then((json) => {
this.setState({
data: json,
});
});
}
render() {
const { data } = this.state;
return (
<div>
<h2> SinglePage </h2>
{!data ? (
<ProgressBar />
) : (
<div>
<Header id={this.props.match.params.id} />
<Details item={data} />
</div>
)}
</div>
);
}
}
export default SinglePage;
Header.js :
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Link, withRouter } from 'react-router-dom';
class Header extends Component {
static propTypes = {
item: PropTypes.shape({
data: PropTypes.string.isRequired,
}).isRequired,
}
render() {
const prev = parseInt(this.props.id) - 1
const next = parseInt(this.props.id) + 1
return (
<div>
<Link to="/"> Retour </Link>
<Link to={`/${prev}`}> Précédent </Link>
<Link to={`/${next}`}> Suivant </Link>
</div>
)
}
}
export default Header;
the solution is pretty-simple. All you need to do is make use of componentWillReceiveProps and check if the param updated, if it did fetch the data again
componentDidMount() {
this.getData(this.props.match.params.id);
}
componentWillReceiveProps(nextProps) {
if(this.props.match.params.id !== nextProps.match.params.id) {
this.getData(nextProps.match.params.id);
}
}
getData = (param) => {
fetch(`http://localhost:1337/${params}`)
.then((res) => res.json())
.then((json) => {
this.setState({
data: json,
});
});
}
I'm new to react + redux. I encountered a problem which my app is not re-render when I dispatch an action. However, I use getState() to examine the state, it did change. I look up documents but still have no idea what the problem is. Please help me, thanks.
The code is as below
====actions.js====
export const ADD_MAIL = 'ADD_MAIL';
export const DEL_MAIL = 'DEL_MAIL';
export function addMail(email) {
return {
type: ADD_MAIL,
email
}
}
export function delMail(id) {
return {
type: DEL_MAIL,
id
}
}
====reducers.js====
import { combineReducers } from 'redux'
import { ADD_MAIL, DEL_MAIL } from '../actions/actions'
import MAILS from '../data'
function emails(state = MAILS, action) {
switch (action.type) {
case ADD_MAIL:
console.log("ADD_MAIL");
return [
action.email,
...state
];
case DEL_MAIL:
let idx = state.length;
let i = 0;
// Find the target mail
while(idx--) {
if (state[idx] && state[idx].serialNo === action.id)
i = idx;
}
let arr1 = state.slice(0, i);
let arr2 = state.slice(i + 1);
let newList = arr1.concat(arr2);
console.log("DEL_MAIL");
return newList;
default:
return state;
}
}
const rootReducer = combineReducers({
emails
});
export default rootReducer;
====main.js====
import React from 'react'
import { render } from 'react-dom'
import { Link } from 'react-router'
import { connect } from 'react-redux'
import { createStore } from 'redux'
import { addMail, delMail } from './actions/actions'
import rootReducer from './reducers/reducers'
import * as btn from './module/button'
import * as module from './module/module'
var store = createStore(rootReducer);
class Inbox extends React.Component {
constructor(props) {
super(props);
this.state = {
searchText: ''
}
this.handleUserInput = this.handleUserInput.bind(this);
this.deleteMail = this.deleteMail.bind(this);
this.sendMail = this.sendMail.bind(this);
}
handleUserInput(searchText) {
this.setState({
searchText: searchText
});
}
deleteMail(obj) {
store.dispatch(delMail(obj.serialNo));
console.log(store.getState());
// This displays the correct new state in console after dispatch
}
sendMail(newMail) {
store.dispatch(addMail(newMail));
console.log(store.getState());
// This displays the correct new state in console after dispatch
}
render() {
let mails = [];
let search = this.state.searchText.toUpperCase();
let emails = this.props.emails;
emails.map(mail => {
if (mail.from.toUpperCase().indexOf(search) !== -1)
mails.push(mail);
});
let sender = (mails.length === emails.length) ? "all" : this.state.searchText;
return (
<div className="main">
<div className="toolbar">
<span>You have {mails.length} message from {sender}.</span>
<module.SearchInput searchText={this.state.searchText} onUserInput={this.handleUserInput} />
<div className="functions">
<btn.AddButton />
</div>
</div>
<div className="mailList">
{mails.map(mail => (
<div className="item" key={mail.serialNo}>
<div className="info sender">
From: {mail.from}
</div>
<div className="info date">
{mail.date}
</div>
<div className="info subject">
Subject: {mail.subject}
</div>
<div className="functions">
<btn.ReadButton serialNo={mail.serialNo} />
<btn.DeleteButton serialNo={mail.serialNo} deleteMail={this.deleteMail} />
</div>
</div>
))}
</div>
<module.NewMailInput sendMail={this.sendMail} />
</div>
);
}
}
function mapStateToProps(state) {
return {
emails: state.emails
};
}
export default connect(mapStateToProps)(Inbox);
====app.js====
import React from 'react'
import { render } from 'react-dom'
import { Router, Route, IndexRoute, browserHistory } from 'react-router'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import { Menu } from './menu'
import { Mail } from './main'
import Inbox from './main'
import rootReducer from './reducers/reducers'
var store = createStore(rootReducer);
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div style={{height: '100%'}}>
<Menu />
{this.props.children}
</div>
);
}
}
class Home extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<Inbox />
);
}
}
render(
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute component={Home} />
<Route path="/inbox" component={Inbox} />
<Route path="/message/:mailSerial" component={Mail} />
</Route>
</Router>
</Provider>,
document.getElementById('app-container'))
Try this:
import React from 'react'
import { render } from 'react-dom'
import { Link } from 'react-router'
import { connect } from 'react-redux'
import { addMail, delMail } from './actions/actions'
import * as btn from './module/button'
import * as module from './module/module'
class Inbox extends React.Component {
constructor(props) {
super(props);
this.state = {
searchText: ''
}
this.handleUserInput = this.handleUserInput.bind(this);
this.deleteMail = this.deleteMail.bind(this);
this.sendMail = this.sendMail.bind(this);
}
handleUserInput(searchText) {
this.setState({
searchText: searchText
});
}
deleteMail(obj) {
this.props.delMail(obj.serialNo); //Call the delMail action
console.log(store.getState());
}
sendMail(newMail) {
this.props.addMail(newMail); //Call the addMail action
console.log(store.getState());
}
render() {
let mails = [];
let search = this.state.searchText.toUpperCase();
let emails = this.props.emails;
emails.map(mail => {
if (mail.from.toUpperCase().indexOf(search) !== -1)
mails.push(mail);
});
let sender = (mails.length === emails.length) ? "all" : this.state.searchText;
return (
<div className="main">
<div className="toolbar">
<span>You have {mails.length} message from {sender}.</span>
<module.SearchInput searchText={this.state.searchText} onUserInput={this.handleUserInput} />
<div className="functions">
<btn.AddButton />
</div>
</div>
<div className="mailList">
{
mails.map(mail => (
<div className="item" key={mail.serialNo}>
<div className="info sender">From: {mail.from}</div>
<div className="info date">{mail.date}</div>
<div className="info subject">Subject: {mail.subject}</div>
<div className="functions">
<btn.ReadButton serialNo={mail.serialNo} />
<btn.DeleteButton serialNo={mail.serialNo} deleteMail={this.deleteMail} />
</div>
</div>
))
}
</div>
<module.NewMailInput sendMail={this.sendMail} />
</div>
);
}
}
function mapStateToProps(state) {
return {
emails: state.emails
};
}
//Connect the component to re-render when state change and
// makes the emails and actions to be available through this.props
export default connect(mapStateToProps, {delMail, addMail})(Inbox);
//To connect Mail component which I suppose that is in another file
function mapStateToProps(state) {
return { emails: state.emails };
}
export default connect(mapStateToProps, {})(Mail);
In your main.js file, you have made a Inbox component. That is a React Component but not a Redux Component.
You have to do something like this while exporting Inbox component.
module.exports = connect((store)=> {
return {emails: store.emails}
})(Inbox)
You have 2x stores: one in main.js and one in app.js. Remove the one in main.js and update the calls to dispatch to use the one passed as props:
class Inbox extends React.Component {
...
deleteMail(obj) {
this.props.dispatch(delMail(obj.serialNo));
}
...
}