I have trouble creating links in my webapp. I'm new to both Flask and React, so apologies if i don't use the correct vocabulary.
When creating a link <Link to='/${todo.id}'>{todo.content}</Link>
, it goes to the url http://localhost:3000/$%7Btodo.id%7D
which is empty. I know %7B is the translation for bracket, but i don't get why it's not taking the value inside.
My App.js
file is the following:
import {BrowserRouter as Router , Routes, Route} from "react-router-dom";
function App() {
console.log('trying')
return (
<div className="App">
<Router>
<Routes>
<Route exact path='/' element={<TodoPage/>}></Route>
<Route path='/:id' element={<Show/>}></Route>
</Routes>
</Router>
</div>
);
}
export default App;
And I have the following functions:
import React from 'react';
import {Link} from "react-router-dom";
export const Card = ({listOfTodos}) => {
return (
<>
{listOfTodos.map(todo => {
return(
<ul key={todo.id}>
<li>
<Link to='/${todo.id}'>{todo.content}</Link>
</li>
</ul>
)
})}
</>
)
}
import React, {useState, useEffect} from 'react';
import {useParams} from "react-router-dom";
export const Show = () => {
const {id} = useParams()
const [todo, setTodo] = useState([])
useEffect( () => {
fetch('/api/'+id)
.then(response => response.json())
.then(data => setTodo(data))
}, [id] ) // [id] means that if the id changes, it makes a new request
return (
<div>
{todo.length >0 && todo.map(data => <div>{data.content}</div>)}
</div>
)
}
And finally I have the flask app:
from flask import Flask, jsonify, request, json
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///example.db"
db = SQLAlchemy(app)
class Todo(db.Model):
id = db.Column(db.Integer, primary_key = True)
content = db.Column(db.Text, nullable = False)
def __str__(self):
return f'{self.id} {self.content}'
def todo_serializer(todo):
return {
'id': todo.id,
'content': todo.content
}
@app.route('/api', methods = ['GET'])
def index():
# will return all the entries in the database
todo = Todo.query.all()
return jsonify([*map( todo_serializer, Todo.query.all() )])
@app.route('/api/<int:id>')
def show(id):
# to click on one to do and have the details
return jsonify([*map(todo_serializer, Todo.query.filter_by(id=id))])
if __name__ == "__main__":
app.run(debug=True)
Thanks in advance !
You have coded the literal string value with the "$"
and bracket character literals.
<Link to='/${todo.id}'>{todo.content}</Link>
In other words, the link target you are navigating to is "/${todo.id}"
, and some of the characters will encoded, e.g. to "/$%7Btodo.id%7D"
.
Use string templates (Template Literals) if you are injecting a todo's id
property into the link target string.
<Link to={`/${todo.id}`}>{todo.content}</Link>
or use the generatePath
utility function to inject the todo's id
into a target path string.
import { generatePath } from 'react-router-dom';
...
<Link to={generatePath("/:id", todo)}> // *
{todo.content}
</Link>
* generatePath("/:id", todo)
works because todo
has an id
property. It's equivalent to generatePath("/:id", { id: todo.id })
.