Reputation: 367
I'm learning redux and I struggle to understand it. I have a list of article and each articles contain title and url. I would like to get the url of the current article and pass it to an other component for show the preview url
I'm trying to pass the url of current article when I click to the button to put on other component in Article.js but it's not working. it's only display all the url of all the article. If someone can help me or explain me what I'm wrong it's could be very nice.
in actions.js
export const articleClick = url => ({
type: SHOW_ARTCILE,
payload: { url }
});
in redux, article.js
article: null
}
const articleReducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
case 'SHOW_ARTCILE':
return [
...state,
{
url: action.url,
}
]
;
default:
return state;
}
}
export default articleReducer;
in Article.js
import { articleClick } from '../../redux/actions';
import { connect } from "react-redux";
class Article extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<p>{this.props.article.title}</p>
<div>
<p>Posted by : {this.props.article.by}</Posted>
<button onClick={() => this.props.articleClick(this.props.article.url), console.log(this.props.article.url)}>Visit website</button>
</div>
</div>
)
}
}
export default connect(
null,
{ articleClick }
)(Article);
in Preview.js
import { connect } from "react-redux";
import { articleClick } from '../../redux/actions';
class PreviewArticle extends Component {
render() {
return (
<p>
{this.url}
</p>
);
}
}
export default connect(
null,
{ articleClick }
)(PreviewArticle);
Upvotes: 1
Views: 1367
Reputation: 15688
Let's try to optimize your react-redux flow here so we can explain things a bit easier.
First let's try to make your App component look like this:
index.js
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore, combineReducers } from "redux";
import articles from "./reducers/articles";
import Articles from "./components/Articles";
import Preview from "./components/Preview";
const store = createStore(
combineReducers({
articles: articles
})
);
function App() {
return (
<Provider store={store}>
<div className="App">
<Articles />
<Preview />
</div>
</Provider>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
The main component displays the Articles component and Preview component. Additionally, we feed the redux-store to the Main component.
Let's take a look at all the aspects that comprise our redux-store.
reducers.js
const initialState = {
articles: [
{
title: "Corgi",
url: "https://www.akc.org/dog-breeds/cardigan-welsh-corgi/"
},
{
title: "Leopard Dog",
url: "https://www.akc.org/dog-breeds/catahoula-leopard-dog/"
}
],
article: {}
};
const articlesReducer = (state = initialState, action) => {
switch (action.type) {
case "SHOW_URL":
return {
...state,
article: action.payload
};
default:
return state;
}
};
export default articlesReducer;
In the reducer, we have a default state that holds an array of objects (articles) and a current article. We'll use both to populate the display of our Articles and Preview components. The only time our reducer will get updated is when an action with a type of "SHOW_URL" is dispatched, and thus we will update the current article.
See action-creator in actions.js:
export const showUrl = article => {
return {
type: "SHOW_URL",
payload: article
};
};
Now for our components, Articles, Article and Preview.
In Articles, we need to use mapStateToProps to get the list of articles available in our Redux-state. Then, we iterate over each article and render an individual Article
component. Passing, the iterated article as a prop.
import React from "react";
import { connect } from "react-redux";
import Article from "./Article";
const Articles = ({ articles }) => {
return (
<div>
{articles.articles.map(article => {
return <Article article={article} />;
})}
</div>
);
};
const mapStateToProps = state => {
return {
articles: state.articles
};
};
export default connect(mapStateToProps)(Articles);
Now in each unique Article component, we use our action-creator, passing in the article we received as a prop to update the redux-state.
import React from "react";
import { connect } from "react-redux";
import { showUrl } from "../actions/articleActions";
const Article = ({ article, showUrl }) => {
return (
<div>
<button onClick={() => showUrl(article)}>{article.title}</button>
</div>
);
};
const mapDispatchToProps = dispatch => {
return {
showUrl: article => {
dispatch(showUrl(article));
}
};
};
export default connect(
null,
mapDispatchToProps
)(Article);
When the action completes, our reducer gets an updated state, which causes our Preview
component to re-render and reflect that updated data.
import React from "react";
import { connect } from "react-redux";
const Preview = ({ articles }) => {
const thisArticle = articles.article;
return (
<div>
<h4>{thisArticle.title}</h4>
<a href={thisArticle.url}>Go To Link</a>
</div>
);
};
const mapStateToProps = state => {
return {
articles: state.articles
};
};
export default connect(mapStateToProps)(Preview);
I've created a sample codesandbox for you here for reference: https://codesandbox.io/s/simple-redux-with-dogs-s1v6h
Upvotes: 1