I have a simple SPA with thunk. It uses github API to get a list of repos. I had previously an example with class presentational component. It had a local state, but I decided to simplify example as much as possible and refactored it to function and removed local state and using ref to get input value. It works fine
Here is the code: https://codesandbox.io/s/k13nowrj33
import React, { Component } from "react";
import ReactDOM from "react-dom";
import { applyMiddleware, combineReducers, createStore } from "redux";
import { connect, Provider } from "react-redux";
import thunk from "redux-thunk";
import "./index.css";
// actions.js
const addRepos = repos => ({ type: "ADD_REPOS", repos });
const clearRepos = () => ({ type: "CLEAR_REPOS" });
const getRepos = username => async dispatch => {
try {
const url = `https://api.github.com/users/${username}/repos`;
const response = await fetch(url);
const responseBody = await response.json();
dispatch(addRepos(responseBody));
} catch (error) {
console.log(error);
dispatch(clearRepos());
}
};
// reducers.js
const repos = (state = [], action) => {
switch (action.type) {
case "ADD_REPOS":
return action.repos;
case "CLEAR_REPOS":
return [];
default:
return state;
}
};
const rootreducer = combineReducers({ repos });
const store = createStore(rootreducer, applyMiddleware(thunk));
// App.js
function App(props) {
var textInput;
var setTextInputRef = element => { textInput = element; };
var submit = () => props.getRepos(textInput.value);
return (
<div>
<h1>Github username: </h1>
<input type="text" ref={setTextInputRef} />
<button onClick={submit}>Get All Repos</button>
<ul>
{props.repos.map((repo, index) => (<li key={index}><a href={repo.html_url}>{repo.name}</a></li> ))}
</ul>
</div>
);
}
// AppContainer.js
const mapStateToProps = state => ({ repos: state.repos });
const mapDispatchToProps = { getRepos };
const AppContainer = connect(mapStateToProps, mapDispatchToProps)(App);
ReactDOM.render(<Provider store={store}><AppContainer /></Provider>, document.getElementById("root"));
1.) You can use defaultValue
for this purpose.
2.) As mentioned in the comments, if you don't use combineReducers()
you'll need to change your mapStateToProps()
.
Here's one way to do it:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import { applyMiddleware, combineReducers, createStore } from "redux";
import { connect, Provider } from "react-redux";
import thunk from "redux-thunk";
import "./index.css";
// actions.js
const addRepos = repos => ({ type: "ADD_REPOS", repos });
const clearRepos = () => ({ type: "CLEAR_REPOS" });
const getRepos = username => async dispatch => {
try {
const url = `https://api.github.com/users/${username}/repos`;
const response = await fetch(url);
const responseBody = await response.json();
dispatch(addRepos(responseBody));
} catch (error) {
console.log(error);
dispatch(clearRepos());
}
};
// reducers.js
const repos = (state = [], action) => {
switch (action.type) {
case "ADD_REPOS":
return action.repos;
case "CLEAR_REPOS":
return [];
default:
return state;
}
};
const store = createStore(repos, applyMiddleware(thunk));
// App.js
function App(props) {
var textInput;
var setTextInputRef = element => {
textInput = element;
};
var submit = () => props.getRepos(textInput.value);
return (
<div>
<h1>Github username: </h1>
<input defaultValue="colinricardo" type="text" ref={setTextInputRef} />
<button onClick={submit}>Get All Repos</button>
<ul>
{props.repos.map((repo, index) => (
<li key={index}>
<a href={repo.html_url}>{repo.name}</a>
</li>
))}
</ul>
</div>
);
}
// AppContainer.js
const mapStateToProps = state => ({ repos: state });
const mapDispatchToProps = { getRepos };
const AppContainer = connect(
mapStateToProps,
mapDispatchToProps
)(App);
ReactDOM.render(
<Provider store={store}>
<AppContainer />
</Provider>,
document.getElementById("root")
);
CodeSandbox here.
To get repos on load:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import { applyMiddleware, combineReducers, createStore } from "redux";
import { connect, Provider } from "react-redux";
import thunk from "redux-thunk";
import "./index.css";
// actions.js
const addRepos = repos => ({ type: "ADD_REPOS", repos });
const clearRepos = () => ({ type: "CLEAR_REPOS" });
const getRepos = username => async dispatch => {
try {
const url = `https://api.github.com/users/${username}/repos`;
const response = await fetch(url);
const responseBody = await response.json();
dispatch(addRepos(responseBody));
} catch (error) {
console.log(error);
dispatch(clearRepos());
}
};
// reducers.js
const repos = (state = [], action) => {
switch (action.type) {
case "ADD_REPOS":
return action.repos;
case "CLEAR_REPOS":
return [];
default:
return state;
}
};
const store = createStore(repos, applyMiddleware(thunk));
// App.js
class App extends React.Component {
componentDidMount() {
this.submit();
}
submit = () => this.props.getRepos(this.textInput.value);
render() {
return (
<div>
<h1>Github username: </h1>
<input
defaultValue="colinricardo"
type="text"
ref={ref => (this.textInput = ref)}
/>
<button onClick={this.submit}>Get All Repos</button>
<ul>
{this.props.repos.map((repo, index) => (
<li key={index}>
<a href={repo.html_url}>{repo.name}</a>
</li>
))}
</ul>
</div>
);
}
}
// AppContainer.js
const mapStateToProps = state => ({ repos: state });
const mapDispatchToProps = { getRepos };
const AppContainer = connect(
mapStateToProps,
mapDispatchToProps
)(App);
ReactDOM.render(
<Provider store={store}>
<AppContainer />
</Provider>,
document.getElementById("root")
);