i'm working on react-redux intermidiate..but i don't know what's going wrong
on this project
hera i have creacted the searchbar for getting car details..and the file is created as 'search.js'...you can see here..
search.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { getCars } from '../actions';
import { bindActionCreators } from 'redux';
class Search extends Component{
constructor(props){
super(props);
this.state = {
keyword:''
}
}
searchCars = (event) => {
event.preventDefault();
this.props.getCars(this.state.keyword)
}
handleChange = (event) => {
this.setState({
keyword:event.target.value
})
}
componentDidMount(){
console.log(this.state);
}
render(){
return(
<div className="main_search">
<form onSubmit={this.searchCars}>
<input type="text" value={this.state.keyword} onChange = {this.handleChange} />
</form>
</div>
)
}
}
// mapStateToProps
// mapDispatchToProps
function mapDispatchToProps(dispatch){
return bindActionCreators({getCars}, dispatch)
}
export default connect(null,mapDispatchToProps)(Search);
and i think error comes from here about getCars..which is described below as s 'index.js'...you can see here
index.js
const URL_ROOT = 'http://localhost:3004'
export default function getCars(keywords){
const request = fetch(`${URL_ROOT}/carsIndex?q=${keywords}`,
{method:'GET'})
.then(response => response.json())
return{
type:'SEARCH_CARS',
payload:request
}
}
and the error looks like this..
and error showing in bundle.js file
so try to fix it and help me...
Please change your mapDispatchToProps method as
const mapDispatchToProps = (dispatch)=> (
bindActionCreators(getCars, dispatch)
)
Related
inside componentDidMount Im calling the dispatched fetchReviews. but once mounted how does the fetched reviews get set in props?
business show component:
import React from "react";
import { Link } from 'react-router-dom';
import Star from "../star/star";
class BusinessShowIndex extends React.Component {
constructor(props) {
super(props)
this.state = {
loading: true
}
}
componentDidMount() {
this.props.fetchReviews(this.props.business.id)
// .then (() => this.setState({reviews: this.props.reviews}))
this.setState({loading: false})
console.log(this.props)
}
render() {
const { business, reviews } = this.props;
if (!this.props.reviews) return null;
if (this.state.loading === true) {
return <p>Loading...</p>
}
return (
<div className="business-show">
<Link to={`/business/${business.id}`} className='link-business-index'>
<img className="business-index-photo" src={business.photo_urls[0]} alt=""/>
<p className="business-index-name">{business.name}</p>
<Star reviews={reviews}/>
<p className="business-index-city">{business.city}</p>
<p className="business-index-cost">Cost: {business.cost}</p>
<p className="business-index-hours">Hours: {business.open} - {business.close}</p>
</Link>
</div>
)
}
};
export default BusinessShowIndex;
container:
import { connect } from 'react-redux';
import {fetchReviews} from '../../actions/review_actions';
import { withRouter } from 'react-router-dom';
import BusinessShowIndex from './business_show_index';
const mapStateToProps = (state, ownProps) => ({
business: state.entities.businesses[ownProps.business.id],
currentUser: state.entities.users[state.session.id],
reviews: Object.values(state.entities.reviews)
})
const mapDispatchToProps = dispatch => ({
fetchReviews: (businessId) => dispatch(fetchReviews(businessId))
})
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(BusinessShowIndex));
let me know what else you need to see! thank you!
also any advice to clean code? taking any suggestions.
Inside componentDidMount Im calling the dispatched fetchReviews. but once mounted how does the fetched reviews get set in props?
You can get using this.props.review
Check your mapStateToProps function. You get the entire state there and it returns whatsever part of it you want to return.
I have a web app that is suppose to show a list of notes made by the user on the dashboard if said list exist (that is if the user wrote any note at all). I wrote the reducer, the actions and I connected state and dispatch in order for it to work. But for some reason the notes created don't appear once in the dashboard when I write them, I already made sure that the ADD_NOTE action gets fired and that the reducer updates the data in redux, but in the dashboard component that data disappears.
This is my reducer.
export default (state = [], action) => {
switch (action.type) {
case "ADD_NOTE":
return [
...state,
action.note
];
case "REMOVE_NOTE":
return state.filter(({ id }) => id !== action.id);
default:
return state;
}
}
And those are my actions
import { v4 as uuidv4 } from 'uuid';
export const addNote = ({ title = "", body = ""} = {}) => ({
type: "ADD_NOTE",
note : {
title,
body,
id : uuidv4()
}
});
export const removeNote = ({ id } = {}) => ({
type: "REMOVE_NOTE",
id
});
This is the component that holds the create note form.
import React, { Component } from 'react';
class CreateNote extends React.Component{
constructor(props){
super(props);
this.onTitleChange = this.onTitleChange.bind(this);
this.onBodyChange = this.onBodyChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
title: "",
body: "",
error: ""
}
}
onTitleChange(e){
const title = e.target.value;
this.setState({ title });
}
onBodyChange(e){
const body = e.target.value;
this.setState({ body });
}
onSubmit(e){
e.preventDefault();
if(!this.state.title || !this.state.body){
this.setState({ error : "Please fill in all gaps"});
} else {
this.setState({ error: ""});
const data = { title: this.state.title, body: this.state.body}
this.props.onChange(data);
}
}
render(){
return(
<div>
{this.state.error && <p>{this.state.error}</p>}
<form onSubmit = {this.onSubmit}>
<label>Put a title for your note</label>
<input
placeholder="Title"
type="text"
value={this.state.title}
autoFocus
onChange = {this.onTitleChange}
/>
<label>Write your note</label>
<textarea
placeholder="Note"
value={this.state.body}
autoFocus
onChange = {this.onBodyChange}
/>
<input type="submit" value="Submit"/>
</form>
</div>
);
}
}
export default CreateNote;
And this is the component that fires the ADD_NOTE action
import React, { Component } from 'react';
import CreateNote from "./actions/CreateNote";
import Header from "./Header";
import { addNote } from "../actions/noteActions"
import { connect } from 'react-redux';
class Create extends React.Component{
constructor(props){
super(props);
this.eventHandler = this.eventHandler.bind(this);
}
eventHandler(data){
this.props.addNote(data);
this.props.history.push("/");
}
render(){
return (
<div>
<Header />
<CreateNote onChange = {this.eventHandler}/>
</div>
)
}
}
const mapDispatchToProps = (dispatch) => ({
addNote: (note) => dispatch(addNote(note))
});
export default connect(null, mapDispatchToProps)(Create);
And finally this is the dashboard component that renders the notes if they exist
import React from "react";
import ListItem from "./actions/ListItem";
import { connect } from 'react-redux';
const ListGroup = (props) => (
<div>
{
props.notes.length === 0 ? <h1>Write a note!</h1> :
(
props.notes.map((note) => {
return <ListItem key={note.id} {...note} />;
})
)
}
</div>
)
// The mapStateToProps does not connect with the local state, the action ADD_NOTE fires whenever
// the Create form is submited and the reducer updates the redux storage. So the problem lies here ?
// It could be that state.note is not definded but I don't know where should I define it if I have to,
// and apparently I don't have to ???????????????
const mapStateToProps = (state) => {
return {
notes: state.note
};
};
export default connect(mapStateToProps)(ListGroup);
When I try to run this it fires an error:
ListGroup.js?11a1:5 Uncaught TypeError: Cannot read property 'length' of undefined
at ListGroup (ListGroup.js?11a1:5)
Showing that the data that gets passed to the props is undefined. I'm thinking that it could be that state.note is not defined and I have to define it somewhere but I don't know if that's the case.
Use Hooks in functional components
connect() is only valid for class based components. For functional components you need to use hooks. Specifically the useSelector hook for reading redux state and useReducer to emit actions. You can find more instructions on redux hooks here https://react-redux.js.org/api/hooks#useselector
** I'm getting an error "TypeError: searchField.toLowerCase is not a function" when trying to run this code whereas the code is compiling successfully**
import React, { Component } from 'react';
import CardList from '../Components/CardList';
import SearchBox from '../Components/SearchBox';
//import { robots } from './robot';
import './App.css';
import Scroll from '../Components/Scroll';
import ErrorBoundry from '../Components/ErrorBoundry';
import { connect } from 'react-redux';
import { searchChange } from '../actions'
const mapStateToProps = state => {
return {searchField:state.searchField}
}
const mapDispatchToProps = (dispatch) =>{
return {
searchField:(event) => dispatch(searchChange(event.target.value))
}
}
class App extends Component {
constructor(){
super()
this.state = {
robots:[]
}
}
componentDidMount() {
fetch('https://jsonplaceholder.typicode.com/users').then(respond =>{
return respond.json()
}).then(users =>{
this.setState({robots:users})
})
}
render(){
const { searchField, onSearchChange } = this.props;
const filterRobots = this.state.robots.filter(robots =>{
//trying to search robot with either upper case or lower case
return robots.name.toLowerCase().includes(searchField.toLowerCase())
});
return(
<div className="tc">
<h1 className="head"> Robo Friend App</h1>
<div>
<SearchBox searchChange={onSearchChange}/>
</div>
<Scroll>
<ErrorBoundry>
<CardList robots={filterRobots} />
</ErrorBoundry>
</Scroll>
</div>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
It appears your mapDispatchToProps function is overriding the searchField prop that is defined in mapStateToProps. So the searchField prop is actually a function instead of a string.
Change your mapDispatchToProps code block from
const mapDispatchToProps = (dispatch) =>{
return {
searchField:(event) => dispatch(searchChange(event.target.value))
}
}
into
const mapDispatchToProps = (dispatch) =>{
return {
onSearchChange:(event) => dispatch(searchChange(event.target.value))
}
}
The problem in your implementation is you are using the same(prop) name for both mapStateToProps and mapDispatchToProps and in this case, later overwrites the first one.
Your filterRobots function tries to run while searchField is still undefined
Try checking searchField value before running the filter like this
const filterRobots = this.state.robots.filter(robots =>{
//*** add the next line
if(!searchField) return undefined
//trying to search robot with either upper case or lower case
return robots.name.toLowerCase().includes(searchField.toLowerCase())
});
This ensures that this line
return robots.name.toLowerCase().includes(searchField.toLowerCase())
only runs if searchField has a value
I made action on my actions folder now I want to access "send new message"
to my handleSubmit function
Below is my action code :
export const types = {
MESSAGES: {
SYNC: 'MESSAGES.SYNC',
NEW: {
CHANGE: 'MESSAGES.NEW.CHANGE',
SEND: 'MESSAGES.NEW.SEND'
}
}
}
export const syncMessages = messages => ({
type: types.MESSAGES.SYNC,
messages
})
export const changeNewMessage = text => ({
type: types.MESSAGES.NEW.CHANGE,
text
})
export const sendNewMessage = () => ({
type: types.MESSAGES.NEW.SEND
})
now I want to access it on my form "handleSubmit" function
Below is my code for message.jsx file
import React from 'react';
import SubMenu from './SubMenu';
import MessageForm from './form/MessageForm';
import * as action from "../../actions/messages.actions";
export default class Messages extends React.PureComponent {
handleSubmit = (e) => {
console.log(e.target.value)
}
render() {
return (
<section className="page-notifications">
<SubMenu/>
<MessageForm onSubmit={this.handleSubmit}/>
</section>
)
}
}
Thanks in advance
import { sendNewMessage } from './path'
class Messages extends React.PureComponent {
handleSubmit = (e) => {
this.props.sendNewMessage();
}
render() {
return (
<section className="page-notifications">
<SubMenu/>
<MessageForm onSubmit={this.handleSubmit}/>
</section>
)
}
}
const mapDispatchToProps = dispatch => {
return {
// dispatching plain actions
sendNewMessage: () => dispatch(sendNewMessage()),
}
}
export default connect(
null,
mapDispatchToProps
)(Messages)
The simple way is to import your store and import dispatch from redux. Then call store.dispatch(action.sendNewMessage). Remember that the store here is your instance of store created using createStore method. But, ideal way to do it is via using react-redux.
I have tried a lot but i couldn't figure out what is the issue.
The props in the component is coming as empty even after adding mapStateToProps and mapDispatchToProps property.Whenever i run the below code i get following error.
projList.js:94 Uncaught TypeError: _this2.props.addNewProj is not a function
My component class is given below:
import React from 'react';
import { addProj } from '../actions';
import { connect } from 'react-redux';
import C from '../constants';
class projList extends React.Component {
constructor(props){
super(props);
this.state = {
title: ''
}
}
render(){
const {title} = this.state;
return(
<section className='proj-list-container'>
<div className='form'>
<label>project Title</label>
<input type='text' onChange={(e)=>{this.setState({title: e.target.value})}}/>
<button className='submit' onClick={()=>{this.props.addNewProj(title)}}>submit</button>
</div>}
</section>
);
}
}
const mapStateToProps = (state, props) =>
({
projLists: state.addProjToList
})
const mapDispatchToProps = dispatch =>
({
addNewProj(projObj) {
dispatch(
addProj(C.ADD_PROJ, projObj)
);
}
});
export default connect (mapStateToProps, mapDispatchToProps)(projList);
export default projList;
My actions file is
import C from './constants'
export const addProj = ({title, endDate}) => {
return ({
type:C.ADD_PROJ,
payload: {
title, endDate
}
})
}
And my store file is :
import C from '../constants';
import { combineReducers } from 'redux';
import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
export const addProjToList = (state=[], action) => {
switch (action.type) {
case C.ADD_PROJ :
return [
...state,
action.payload
]
default : return state
}
}
const appReducer = combineReducers({
addProjToList
});
export default (initialState={projList: []}) => {
return applyMiddleware(thunk)(createStore)(appReducer, initialState);
}
any help would be greatly appreciated. Thanks!